* [PATCH 1/5] gdb/amd-dbgapi: remove unnecessary AMD_DBGAPI_EVENT_KIND_NONE argument
@ 2025-06-05 20:16 Simon Marchi
2025-06-05 20:16 ` [PATCH 2/5] gdb/amd-dbgapi: add assert in require_forward_progress Simon Marchi
` (4 more replies)
0 siblings, 5 replies; 12+ messages in thread
From: Simon Marchi @ 2025-06-05 20:16 UTC (permalink / raw)
To: gdb-patches; +Cc: Lancelot Six, Simon Marchi
Rely on the default value.
Change-Id: I08c683de005806c5c5d29ed7f9b0c6de81b49a01
---
gdb/amd-dbgapi-target.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
index 8e067b66bd86..c11e834aa408 100644
--- a/gdb/amd-dbgapi-target.c
+++ b/gdb/amd-dbgapi-target.c
@@ -1473,7 +1473,7 @@ amd_dbgapi_target::wait (ptid_t ptid, struct target_waitstatus *ws,
/* Drain the events for the current inferior from the amd_dbgapi and
preserve the ordering. */
auto info = get_amd_dbgapi_inferior_info (current_inferior ());
- process_event_queue (info->process_id, AMD_DBGAPI_EVENT_KIND_NONE);
+ process_event_queue (info->process_id);
std::tie (event_ptid, gpu_waitstatus) = consume_one_event (ptid.pid ());
if (event_ptid == minus_one_ptid)
base-commit: f118937c181f008f78496d299873c879648d2d1a
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 2/5] gdb/amd-dbgapi: add assert in require_forward_progress
2025-06-05 20:16 [PATCH 1/5] gdb/amd-dbgapi: remove unnecessary AMD_DBGAPI_EVENT_KIND_NONE argument Simon Marchi
@ 2025-06-05 20:16 ` Simon Marchi
2025-06-06 10:06 ` Lancelot SIX
2025-06-05 20:16 ` [PATCH 3/5] gdb/amd-dbgapi: pass amd_dbgapi_inferior_info to process_event_queue Simon Marchi
` (3 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Simon Marchi @ 2025-06-05 20:16 UTC (permalink / raw)
To: gdb-patches; +Cc: Lancelot Six, Simon Marchi
I didn't have a problem in this area, but it seems to me that this
pre-condition should always hold. We should only disable forward
progress requirement if the target says it's ok to do so. Otherwise, we
could get in a situation where we wait for events from amd-dbgapi, which
will never arrive, because amd-dbgapi didn't actually resume things.
Change-Id: Ifc49f55c7874924b7c47888b8391a07a01d960fc
---
gdb/amd-dbgapi-target.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
index c11e834aa408..8fd8bcf5ae49 100644
--- a/gdb/amd-dbgapi-target.c
+++ b/gdb/amd-dbgapi-target.c
@@ -450,6 +450,12 @@ static void
require_forward_progress (ptid_t ptid, process_stratum_target *proc_target,
bool require)
{
+ /* If we try to disable forward progress requirement but the target expects
+ resumed threads to be committed to the target, we could wait for events
+ that will never arrive. */
+ if (!require)
+ gdb_assert (!proc_target->commit_resumed_state);
+
for (inferior *inf : all_inferiors (proc_target))
{
if (ptid != minus_one_ptid && inf->pid != ptid.pid ())
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 3/5] gdb/amd-dbgapi: pass amd_dbgapi_inferior_info to process_event_queue
2025-06-05 20:16 [PATCH 1/5] gdb/amd-dbgapi: remove unnecessary AMD_DBGAPI_EVENT_KIND_NONE argument Simon Marchi
2025-06-05 20:16 ` [PATCH 2/5] gdb/amd-dbgapi: add assert in require_forward_progress Simon Marchi
@ 2025-06-05 20:16 ` Simon Marchi
2025-06-06 11:00 ` Lancelot SIX
2025-06-05 20:16 ` [PATCH 4/5] gdb/amd-dbgapi: factor out require_forward_progress overload to target one inferior Simon Marchi
` (2 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Simon Marchi @ 2025-06-05 20:16 UTC (permalink / raw)
To: gdb-patches; +Cc: Lancelot Six, Simon Marchi
A following patch will make process_event_queue access a field of
amd_dbgapi_inferior_info. Prepare for this by making
process_event_queue accept an amd_dbgapi_inferior_info object, instead
of a process id.
Change-Id: I9adc491dd1ff64ff74c40aa7662fffb11bd8332b
---
gdb/amd-dbgapi-target.c | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)
diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
index 8fd8bcf5ae49..1ec20d1874ec 100644
--- a/gdb/amd-dbgapi-target.c
+++ b/gdb/amd-dbgapi-target.c
@@ -234,7 +234,7 @@ struct amd_dbgapi_inferior_info
};
static amd_dbgapi_event_id_t process_event_queue
- (amd_dbgapi_process_id_t process_id,
+ (amd_dbgapi_inferior_info &info,
amd_dbgapi_event_kind_t until_event_kind = AMD_DBGAPI_EVENT_KIND_NONE);
static const target_info amd_dbgapi_target_info = {
@@ -564,8 +564,7 @@ amd_dbgapi_target_breakpoint::check_status (struct bpstat *bs)
/* If the action is AMD_DBGAPI_BREAKPOINT_ACTION_HALT, we need to wait until
a breakpoint resume event for this breakpoint_id is seen. */
amd_dbgapi_event_id_t resume_event_id
- = process_event_queue (info->process_id,
- AMD_DBGAPI_EVENT_KIND_BREAKPOINT_RESUME);
+ = process_event_queue (*info, AMD_DBGAPI_EVENT_KIND_BREAKPOINT_RESUME);
/* We should always get a breakpoint_resume event after processing all
events generated by reporting the breakpoint hit. */
@@ -1337,28 +1336,22 @@ event_kind_str (amd_dbgapi_event_kind_t kind)
gdb_assert_not_reached ("unhandled amd_dbgapi_event_kind_t value");
}
-/* Drain the dbgapi event queue of a given process_id, or of all processes if
- process_id is AMD_DBGAPI_PROCESS_NONE. Stop processing the events if an
- event of a given kind is requested and `process_id` is not
- AMD_DBGAPI_PROCESS_NONE. Wave stop events that are not returned are queued
- into their inferior's amd_dbgapi_inferior_info pending wave events. */
+/* Drain the dbgapi event queue of a given process_id. Stop processing the
+ events if an event of a given kind is requested (not AMD_DBGAPI_EVENT_NONE).
+ Wave stop events that are not returned are queued into their inferior's
+ amd_dbgapi_inferior_info pending wave events. */
static amd_dbgapi_event_id_t
-process_event_queue (amd_dbgapi_process_id_t process_id,
+process_event_queue (amd_dbgapi_inferior_info &info,
amd_dbgapi_event_kind_t until_event_kind)
{
- /* An event of a given type can only be requested from a single
- process_id. */
- gdb_assert (until_event_kind == AMD_DBGAPI_EVENT_KIND_NONE
- || process_id != AMD_DBGAPI_PROCESS_NONE);
-
while (true)
{
amd_dbgapi_event_id_t event_id;
amd_dbgapi_event_kind_t event_kind;
amd_dbgapi_status_t status
- = amd_dbgapi_process_next_pending_event (process_id, &event_id,
+ = amd_dbgapi_process_next_pending_event (info.process_id, &event_id,
&event_kind);
if (status != AMD_DBGAPI_STATUS_SUCCESS)
@@ -1479,7 +1472,7 @@ amd_dbgapi_target::wait (ptid_t ptid, struct target_waitstatus *ws,
/* Drain the events for the current inferior from the amd_dbgapi and
preserve the ordering. */
auto info = get_amd_dbgapi_inferior_info (current_inferior ());
- process_event_queue (info->process_id);
+ process_event_queue (*info);
std::tie (event_ptid, gpu_waitstatus) = consume_one_event (ptid.pid ());
if (event_ptid == minus_one_ptid)
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 4/5] gdb/amd-dbgapi: factor out require_forward_progress overload to target one inferior
2025-06-05 20:16 [PATCH 1/5] gdb/amd-dbgapi: remove unnecessary AMD_DBGAPI_EVENT_KIND_NONE argument Simon Marchi
2025-06-05 20:16 ` [PATCH 2/5] gdb/amd-dbgapi: add assert in require_forward_progress Simon Marchi
2025-06-05 20:16 ` [PATCH 3/5] gdb/amd-dbgapi: pass amd_dbgapi_inferior_info to process_event_queue Simon Marchi
@ 2025-06-05 20:16 ` Simon Marchi
2025-06-06 13:36 ` Lancelot SIX
2025-06-05 20:16 ` [PATCH 5/5] gdb/amd-dbgapi: disable forward progress requirement in amd_dbgapi_target_breakpoint::check_status Simon Marchi
2025-06-06 9:59 ` [PATCH 1/5] gdb/amd-dbgapi: remove unnecessary AMD_DBGAPI_EVENT_KIND_NONE argument Lancelot SIX
4 siblings, 1 reply; 12+ messages in thread
From: Simon Marchi @ 2025-06-05 20:16 UTC (permalink / raw)
To: gdb-patches; +Cc: Lancelot Six, Simon Marchi
A following patch will want to call require_forward_progress for a given
inferior. Extract a new require_forward_progress overload from the
existing require_forward_progress function that targets a specific
inferior.
Change-Id: I54f42b83eb8443d4d91747ffbc86eaeb017f1e49
---
gdb/amd-dbgapi-target.c | 49 +++++++++++++++++++++++------------------
1 file changed, 28 insertions(+), 21 deletions(-)
diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
index 1ec20d1874ec..e86d7f34d0f6 100644
--- a/gdb/amd-dbgapi-target.c
+++ b/gdb/amd-dbgapi-target.c
@@ -443,6 +443,32 @@ async_event_handler_mark ()
mark_async_event_handler (amd_dbgapi_async_event_handler);
}
+/* Set forward progress requirement to REQUIRE for inferior INFO. */
+
+static void
+require_forward_progress (amd_dbgapi_inferior_info &info, bool require)
+{
+ /* If we try to disable forward progress requirement but the target expects
+ resumed threads to be committed to the target, we could wait for events
+ that will never arrive. */
+ if (!require)
+ gdb_assert (!info.inf->process_target ()->commit_resumed_state);
+
+ gdb_assert (info.process_id != AMD_DBGAPI_PROCESS_NONE);
+
+ /* Don't do unnecessary calls to amd-dbgapi to avoid polluting the logs. */
+ if (info.forward_progress_required == require)
+ return;
+
+ const auto progress
+ = require ? AMD_DBGAPI_PROGRESS_NORMAL : AMD_DBGAPI_PROGRESS_NO_FORWARD;
+ const auto status
+ = amd_dbgapi_process_set_progress (info.process_id, progress);
+ gdb_assert (status == AMD_DBGAPI_STATUS_SUCCESS);
+
+ info.forward_progress_required = require;
+}
+
/* Set forward progress requirement to REQUIRE for all processes of PROC_TARGET
matching PTID. */
@@ -450,12 +476,6 @@ static void
require_forward_progress (ptid_t ptid, process_stratum_target *proc_target,
bool require)
{
- /* If we try to disable forward progress requirement but the target expects
- resumed threads to be committed to the target, we could wait for events
- that will never arrive. */
- if (!require)
- gdb_assert (!proc_target->commit_resumed_state);
-
for (inferior *inf : all_inferiors (proc_target))
{
if (ptid != minus_one_ptid && inf->pid != ptid.pid ())
@@ -463,21 +483,8 @@ require_forward_progress (ptid_t ptid, process_stratum_target *proc_target,
amd_dbgapi_inferior_info *info = get_amd_dbgapi_inferior_info (inf);
- if (info->process_id == AMD_DBGAPI_PROCESS_NONE)
- continue;
-
- /* Don't do unnecessary calls to amd-dbgapi to avoid polluting the logs. */
- if (info->forward_progress_required == require)
- continue;
-
- amd_dbgapi_status_t status
- = amd_dbgapi_process_set_progress
- (info->process_id, (require
- ? AMD_DBGAPI_PROGRESS_NORMAL
- : AMD_DBGAPI_PROGRESS_NO_FORWARD));
- gdb_assert (status == AMD_DBGAPI_STATUS_SUCCESS);
-
- info->forward_progress_required = require;
+ if (info->process_id != AMD_DBGAPI_PROCESS_NONE)
+ require_forward_progress (*info, require);
/* If ptid targets a single inferior and we have found it, no need to
continue. */
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 5/5] gdb/amd-dbgapi: disable forward progress requirement in amd_dbgapi_target_breakpoint::check_status
2025-06-05 20:16 [PATCH 1/5] gdb/amd-dbgapi: remove unnecessary AMD_DBGAPI_EVENT_KIND_NONE argument Simon Marchi
` (2 preceding siblings ...)
2025-06-05 20:16 ` [PATCH 4/5] gdb/amd-dbgapi: factor out require_forward_progress overload to target one inferior Simon Marchi
@ 2025-06-05 20:16 ` Simon Marchi
2025-06-06 13:58 ` Lancelot SIX
2025-06-06 9:59 ` [PATCH 1/5] gdb/amd-dbgapi: remove unnecessary AMD_DBGAPI_EVENT_KIND_NONE argument Lancelot SIX
4 siblings, 1 reply; 12+ messages in thread
From: Simon Marchi @ 2025-06-05 20:16 UTC (permalink / raw)
To: gdb-patches; +Cc: Lancelot Six, Simon Marchi
ROCgdb handles target events very slowly when running a test case like
this, where a breakpoint is preset on HipTest::vectorADD:
for (int i=0; i < numDevices; ++i) {
HIPCHECK(hipSetDevice(i));
hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock), 0, stream[i],
static_cast<const int*>(A_d[i]), static_cast<const int*>(B_d[i]), C_d[i], N);
}
What happens is:
- A kernel is launched
- The internal runtime breakpoint is hit during the second
hipLaunchKernelGGL call, which causes
amd_dbgapi_target_breakpoint::check_status to be called
- Meanwhile, all waves of the kernel hit the breakpoint on vectorADD
- amd_dbgapi_target_breakpoint::check_status calls process_event_queue,
which pulls the thousand of breakpoint hit events from the kernel
- As part of handling the breakpoint hit events, we write the PC of the
waves that stopped to decrement it. Because the forward progress
requirement is not disabled, this causes a suspend/resume of the
queue each time, which is time-consuming.
The stack trace where this all happens is:
#32 0x00007ffff6b9abda in amd_dbgapi_write_register (wave_id=..., register_id=..., offset=0, value_size=8, value=0x7fffea9fdcc0) at /home/smarchi/src/amd-dbgapi/src/register.cpp:587
#33 0x00005555588c0bed in amd_dbgapi_target::store_registers (this=0x55555c7b1d20 <the_amd_dbgapi_target>, regcache=0x507000002240, regno=470) at /home/smarchi/src/wt/amd/gdb/amd-dbgapi-target.c:2504
#34 0x000055555a5186a1 in target_store_registers (regcache=0x507000002240, regno=470) at /home/smarchi/src/wt/amd/gdb/target.c:3973
#35 0x0000555559fab831 in regcache::raw_write (this=0x507000002240, regnum=470, src=...) at /home/smarchi/src/wt/amd/gdb/regcache.c:890
#36 0x0000555559fabd2b in regcache::cooked_write (this=0x507000002240, regnum=470, src=...) at /home/smarchi/src/wt/amd/gdb/regcache.c:915
#37 0x0000555559fc3ca5 in regcache::cooked_write<unsigned long, void> (this=0x507000002240, regnum=470, val=140737323456768) at /home/smarchi/src/wt/amd/gdb/regcache.c:850
#38 0x0000555559fab09a in regcache_cooked_write_unsigned (regcache=0x507000002240, regnum=470, val=140737323456768) at /home/smarchi/src/wt/amd/gdb/regcache.c:858
#39 0x0000555559fb0678 in regcache_write_pc (regcache=0x507000002240, pc=0x7ffff62bd900) at /home/smarchi/src/wt/amd/gdb/regcache.c:1460
#40 0x00005555588bb37d in process_one_event (event_id=..., event_kind=AMD_DBGAPI_EVENT_KIND_WAVE_STOP) at /home/smarchi/src/wt/amd/gdb/amd-dbgapi-target.c:1873
#41 0x00005555588bbf7b in process_event_queue (process_id=..., until_event_kind=AMD_DBGAPI_EVENT_KIND_BREAKPOINT_RESUME) at /home/smarchi/src/wt/amd/gdb/amd-dbgapi-target.c:2006
#42 0x00005555588b1aca in amd_dbgapi_target_breakpoint::check_status (this=0x511000140900, bs=0x50600014ed00) at /home/smarchi/src/wt/amd/gdb/amd-dbgapi-target.c:890
#43 0x0000555558c50080 in bpstat_stop_status (aspace=0x5070000061b0, bp_addr=0x7fffed0b9ab0, thread=0x518000026c80, ws=..., stop_chain=0x50600014ed00) at /home/smarchi/src/wt/amd/gdb/breakpoint.c:6126
#44 0x000055555984f4ff in handle_signal_stop (ecs=0x7fffeaa40ef0) at /home/smarchi/src/wt/amd/gdb/infrun.c:7169
#45 0x000055555984b889 in handle_inferior_event (ecs=0x7fffeaa40ef0) at /home/smarchi/src/wt/amd/gdb/infrun.c:6621
#46 0x000055555983eab6 in fetch_inferior_event () at /home/smarchi/src/wt/amd/gdb/infrun.c:4750
#47 0x00005555597caa5f in inferior_event_handler (event_type=INF_REG_EVENT) at /home/smarchi/src/wt/amd/gdb/inf-loop.c:42
#48 0x00005555588b838e in handle_target_event (client_data=0x0) at /home/smarchi/src/wt/amd/gdb/amd-dbgapi-target.c:1513
Fix that performance problem by disabling the forward progress
requirement in amd_dbgapi_target_breakpoint::check_status, before
calling process_event_queue, so that we can process all events
efficiently.
Since the same performance problem could theoritically happen any time
process_event_queue is called with forward progress requirement enabled,
add an assert to ensure that forward progress requirement is disabled
when process_event_queue is invoked. This makes it necessary to add a
require_forward_progress call to amd_dbgapi_finalize_core_attach. It
looks a bit strange, since core files don't have execution, but it
doesn't hurt.
Add a test that replicates this scenario. The test launches a kernel
that hits a breakpoint (with an always false condition) repeatedly.
Meanwhile, the host process loads an unloads a code object, causing
check_status to be called.
Bug: SWDEV-482511
Change-Id: Ida86340d679e6bd8462712953458c07ba3fd49ec
---
gdb/amd-dbgapi-target.c | 6 ++
.../code-object-load-while-breakpoint-hit.cpp | 70 +++++++++++++++++++
.../code-object-load-while-breakpoint-hit.exp | 68 ++++++++++++++++++
3 files changed, 144 insertions(+)
create mode 100644 gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.cpp
create mode 100644 gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.exp
diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
index e86d7f34d0f6..44913bbd7532 100644
--- a/gdb/amd-dbgapi-target.c
+++ b/gdb/amd-dbgapi-target.c
@@ -568,6 +568,8 @@ amd_dbgapi_target_breakpoint::check_status (struct bpstat *bs)
if (action == AMD_DBGAPI_BREAKPOINT_ACTION_RESUME)
return;
+ require_forward_progress (*info, false);
+
/* If the action is AMD_DBGAPI_BREAKPOINT_ACTION_HALT, we need to wait until
a breakpoint resume event for this breakpoint_id is seen. */
amd_dbgapi_event_id_t resume_event_id
@@ -1352,6 +1354,10 @@ static amd_dbgapi_event_id_t
process_event_queue (amd_dbgapi_inferior_info &info,
amd_dbgapi_event_kind_t until_event_kind)
{
+ /* Pulling events with forward progress required may result in bad
+ performance, make sure it is not required. */
+ gdb_assert (!info.forward_progress_required);
+
while (true)
{
amd_dbgapi_event_id_t event_id;
diff --git a/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.cpp b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.cpp
new file mode 100644
index 000000000000..e97809335569
--- /dev/null
+++ b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.cpp
@@ -0,0 +1,70 @@
+#ifdef DEVICE
+
+#include <hip/hip_runtime.h>
+
+constexpr unsigned int NUM_BREAKPOINT_HITS = 5;
+
+static __device__ void
+break_here ()
+{
+ asm ("s_nop 0");
+}
+
+extern "C" __global__ void
+kernel ()
+{
+ for (int n = 0; n < NUM_BREAKPOINT_HITS; ++n)
+ break_here ();
+}
+
+#else
+
+#include <hip/hip_runtime.h>
+#include <unistd.h>
+
+constexpr unsigned int NUM_ITEMS_PER_BLOCK = 256;
+constexpr unsigned int NUM_BLOCKS = 128;
+constexpr unsigned int NUM_ITEMS = NUM_ITEMS_PER_BLOCK * NUM_BLOCKS;
+constexpr unsigned int NUM_LOAD_UNLOADS = 5;
+
+#define CHECK(cmd) \
+ { \
+ hipError_t error = cmd; \
+ if (error != hipSuccess) \
+ { \
+ fprintf (stderr, "error: '%s'(%d) at %s:%d\n", \
+ hipGetErrorString (error), error, __FILE__, __LINE__); \
+ exit (EXIT_FAILURE); \
+ } \
+ }
+
+int
+main (int argc, const char **argv)
+{
+ if (argc != 2)
+ {
+ fprintf (stderr, "Usage: %s <hip_module_path>\n", argv[0]);
+ return 1;
+ }
+
+ const auto module_path = argv[1];
+ hipModule_t module;
+ CHECK (hipModuleLoad (&module, module_path));
+
+ /* Launch the kernel. */
+ hipFunction_t function;
+ CHECK (hipModuleGetFunction (&function, module, "kernel"));
+ CHECK (hipModuleLaunchKernel (function, NUM_BLOCKS, 1, 1,
+ NUM_ITEMS_PER_BLOCK, 1, 1, 0, nullptr, nullptr,
+ nullptr));
+
+ /* Load and unload the module many times. */
+ for (int i = 0; i < NUM_LOAD_UNLOADS; ++i)
+ {
+ hipModule_t dummy_module;
+ CHECK (hipModuleLoad (&dummy_module, module_path));
+ CHECK (hipModuleUnload (dummy_module));
+ }
+}
+
+#endif
diff --git a/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.exp b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.exp
new file mode 100644
index 000000000000..b8d003f37032
--- /dev/null
+++ b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.exp
@@ -0,0 +1,68 @@
+# Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
+
+# This file is part of GDB.
+
+# 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; either version 3 of the License, or
+# (at your option) any later version.
+
+# 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, see <http://www.gnu.org/licenses/>.
+
+# This test verifies what happens when a code object list update happens at the
+# same time as some wave stop events are reported. It was added following a
+# performance bug fix, where forward progress requirement disabled when
+# pulling events from amd-dbgapi in amd_dbgapi_target_breakpoint::check_status.
+#
+# The test launches a kernel that hits a breakpoint with an always false
+# condition a certain number of times. Meanwhile, the host loads and unloads
+# a code object in a loop, causing check_status to be called. The hope is that
+# check_status, when calling process_event_queue, will pull many WAVE_STOP
+# events from the kernel hitting the breakpoint.
+#
+# Without the appropriate fix (of disabling forward progress requirement in
+# check_status), GDB would hit the newly-added assert in process_event_queue,
+# which verifies that forward progress requirement is disabled. Even without
+# this assert, the test would likely time out (depending on the actual timeout
+# value).
+
+load_lib rocm.exp
+standard_testfile .cpp
+require allow_hipcc_tests
+
+# Build the host executable.
+if { [build_executable "failed to prepare" \
+ $testfile $srcfile {debug hip}] == -1 } {
+ return -1
+}
+
+set hipmodule_path [standard_output_file ${testfile}.co]
+
+# Build the kernel object file.
+if { [gdb_compile $srcdir/$subdir/$srcfile \
+ $hipmodule_path object \
+ { debug hip additional_flags=--genco additional_flags=-DDEVICE } ] != "" } {
+ return -1
+}
+
+proc do_test { } {
+ with_rocm_gpu_lock {
+ clean_restart $::binfile
+ gdb_test_no_output "set args $::hipmodule_path" "set args"
+
+ if { ![runto_main] } {
+ return
+ }
+
+ gdb_test "with breakpoint pending on -- break break_here if 0"
+ gdb_continue_to_end "continue to end" "continue" 1
+ }
+}
+
+do_test
--
2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/5] gdb/amd-dbgapi: remove unnecessary AMD_DBGAPI_EVENT_KIND_NONE argument
2025-06-05 20:16 [PATCH 1/5] gdb/amd-dbgapi: remove unnecessary AMD_DBGAPI_EVENT_KIND_NONE argument Simon Marchi
` (3 preceding siblings ...)
2025-06-05 20:16 ` [PATCH 5/5] gdb/amd-dbgapi: disable forward progress requirement in amd_dbgapi_target_breakpoint::check_status Simon Marchi
@ 2025-06-06 9:59 ` Lancelot SIX
4 siblings, 0 replies; 12+ messages in thread
From: Lancelot SIX @ 2025-06-06 9:59 UTC (permalink / raw)
To: Simon Marchi; +Cc: gdb-patches
On Thu, Jun 05, 2025 at 04:16:24PM -0400, Simon Marchi wrote:
> Rely on the default value.
Hi,
This OK.
Approved-By: Lancelot Six <lancelot.six@amd.com> (amdgpu).
Best,
Lancelot.
>
> Change-Id: I08c683de005806c5c5d29ed7f9b0c6de81b49a01
> ---
> gdb/amd-dbgapi-target.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
> index 8e067b66bd86..c11e834aa408 100644
> --- a/gdb/amd-dbgapi-target.c
> +++ b/gdb/amd-dbgapi-target.c
> @@ -1473,7 +1473,7 @@ amd_dbgapi_target::wait (ptid_t ptid, struct target_waitstatus *ws,
> /* Drain the events for the current inferior from the amd_dbgapi and
> preserve the ordering. */
> auto info = get_amd_dbgapi_inferior_info (current_inferior ());
> - process_event_queue (info->process_id, AMD_DBGAPI_EVENT_KIND_NONE);
> + process_event_queue (info->process_id);
>
> std::tie (event_ptid, gpu_waitstatus) = consume_one_event (ptid.pid ());
> if (event_ptid == minus_one_ptid)
>
> base-commit: f118937c181f008f78496d299873c879648d2d1a
> --
> 2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/5] gdb/amd-dbgapi: add assert in require_forward_progress
2025-06-05 20:16 ` [PATCH 2/5] gdb/amd-dbgapi: add assert in require_forward_progress Simon Marchi
@ 2025-06-06 10:06 ` Lancelot SIX
0 siblings, 0 replies; 12+ messages in thread
From: Lancelot SIX @ 2025-06-06 10:06 UTC (permalink / raw)
To: Simon Marchi; +Cc: gdb-patches
On Thu, Jun 05, 2025 at 04:16:25PM -0400, Simon Marchi wrote:
> I didn't have a problem in this area, but it seems to me that this
> pre-condition should always hold. We should only disable forward
> progress requirement if the target says it's ok to do so. Otherwise, we
> could get in a situation where we wait for events from amd-dbgapi, which
> will never arrive, because amd-dbgapi didn't actually resume things.
>
This is OK.
Approved-by: Lancelot Six <lancelot.six@amd.com> (amdgpu)
Best,
Lancelot
> Change-Id: Ifc49f55c7874924b7c47888b8391a07a01d960fc
> ---
> gdb/amd-dbgapi-target.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
> index c11e834aa408..8fd8bcf5ae49 100644
> --- a/gdb/amd-dbgapi-target.c
> +++ b/gdb/amd-dbgapi-target.c
> @@ -450,6 +450,12 @@ static void
> require_forward_progress (ptid_t ptid, process_stratum_target *proc_target,
> bool require)
> {
> + /* If we try to disable forward progress requirement but the target expects
> + resumed threads to be committed to the target, we could wait for events
> + that will never arrive. */
> + if (!require)
> + gdb_assert (!proc_target->commit_resumed_state);
> +
> for (inferior *inf : all_inferiors (proc_target))
> {
> if (ptid != minus_one_ptid && inf->pid != ptid.pid ())
> --
> 2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 3/5] gdb/amd-dbgapi: pass amd_dbgapi_inferior_info to process_event_queue
2025-06-05 20:16 ` [PATCH 3/5] gdb/amd-dbgapi: pass amd_dbgapi_inferior_info to process_event_queue Simon Marchi
@ 2025-06-06 11:00 ` Lancelot SIX
2025-06-09 15:36 ` Simon Marchi
0 siblings, 1 reply; 12+ messages in thread
From: Lancelot SIX @ 2025-06-06 11:00 UTC (permalink / raw)
To: Simon Marchi; +Cc: gdb-patches
On Thu, Jun 05, 2025 at 04:16:26PM -0400, Simon Marchi wrote:
> A following patch will make process_event_queue access a field of
> amd_dbgapi_inferior_info. Prepare for this by making
> process_event_queue accept an amd_dbgapi_inferior_info object, instead
> of a process id.
>
> Change-Id: I9adc491dd1ff64ff74c40aa7662fffb11bd8332b
> ---
> gdb/amd-dbgapi-target.c | 25 +++++++++----------------
> 1 file changed, 9 insertions(+), 16 deletions(-)
>
> diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
> index 8fd8bcf5ae49..1ec20d1874ec 100644
> --- a/gdb/amd-dbgapi-target.c
> +++ b/gdb/amd-dbgapi-target.c
> @@ -234,7 +234,7 @@ struct amd_dbgapi_inferior_info
> };
>
> static amd_dbgapi_event_id_t process_event_queue
> - (amd_dbgapi_process_id_t process_id,
> + (amd_dbgapi_inferior_info &info,
> amd_dbgapi_event_kind_t until_event_kind = AMD_DBGAPI_EVENT_KIND_NONE);
>
> static const target_info amd_dbgapi_target_info = {
> @@ -564,8 +564,7 @@ amd_dbgapi_target_breakpoint::check_status (struct bpstat *bs)
> /* If the action is AMD_DBGAPI_BREAKPOINT_ACTION_HALT, we need to wait until
> a breakpoint resume event for this breakpoint_id is seen. */
> amd_dbgapi_event_id_t resume_event_id
> - = process_event_queue (info->process_id,
> - AMD_DBGAPI_EVENT_KIND_BREAKPOINT_RESUME);
> + = process_event_queue (*info, AMD_DBGAPI_EVENT_KIND_BREAKPOINT_RESUME);
>
> /* We should always get a breakpoint_resume event after processing all
> events generated by reporting the breakpoint hit. */
> @@ -1337,28 +1336,22 @@ event_kind_str (amd_dbgapi_event_kind_t kind)
> gdb_assert_not_reached ("unhandled amd_dbgapi_event_kind_t value");
> }
>
> -/* Drain the dbgapi event queue of a given process_id, or of all processes if
> - process_id is AMD_DBGAPI_PROCESS_NONE. Stop processing the events if an
> - event of a given kind is requested and `process_id` is not
> - AMD_DBGAPI_PROCESS_NONE. Wave stop events that are not returned are queued
> - into their inferior's amd_dbgapi_inferior_info pending wave events. */
> +/* Drain the dbgapi event queue of a given process_id. Stop processing the
It reads odd to have process_id here, as we don't pass it as an explicit
parameter anymore. Could it say "a given inferior" instead?
> + events if an event of a given kind is requested (not AMD_DBGAPI_EVENT_NONE).
> + Wave stop events that are not returned are queued into their inferior's
> + amd_dbgapi_inferior_info pending wave events. */
My first intuition when reading this patch was "hey, the INFO param is
never modified, why not use a const ref". But eventually ,under
process_one_event, we'll grab a reference to the INFO and modify it to
stash stop events.
Should this patch go one step further, and have the INFO passed to
process_one_event (this one can ensure the event's process_id matches
the INFO's process_id)? This would also save iterating over all
inferiors to find the one we are looking for.
Best,
Lancelot.
>
> static amd_dbgapi_event_id_t
> -process_event_queue (amd_dbgapi_process_id_t process_id,
> +process_event_queue (amd_dbgapi_inferior_info &info,
> amd_dbgapi_event_kind_t until_event_kind)
> {
> - /* An event of a given type can only be requested from a single
> - process_id. */
> - gdb_assert (until_event_kind == AMD_DBGAPI_EVENT_KIND_NONE
> - || process_id != AMD_DBGAPI_PROCESS_NONE);
> -
> while (true)
> {
> amd_dbgapi_event_id_t event_id;
> amd_dbgapi_event_kind_t event_kind;
>
> amd_dbgapi_status_t status
> - = amd_dbgapi_process_next_pending_event (process_id, &event_id,
> + = amd_dbgapi_process_next_pending_event (info.process_id, &event_id,
> &event_kind);
>
> if (status != AMD_DBGAPI_STATUS_SUCCESS)
> @@ -1479,7 +1472,7 @@ amd_dbgapi_target::wait (ptid_t ptid, struct target_waitstatus *ws,
> /* Drain the events for the current inferior from the amd_dbgapi and
> preserve the ordering. */
> auto info = get_amd_dbgapi_inferior_info (current_inferior ());
> - process_event_queue (info->process_id);
> + process_event_queue (*info);
>
> std::tie (event_ptid, gpu_waitstatus) = consume_one_event (ptid.pid ());
> if (event_ptid == minus_one_ptid)
> --
> 2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 4/5] gdb/amd-dbgapi: factor out require_forward_progress overload to target one inferior
2025-06-05 20:16 ` [PATCH 4/5] gdb/amd-dbgapi: factor out require_forward_progress overload to target one inferior Simon Marchi
@ 2025-06-06 13:36 ` Lancelot SIX
0 siblings, 0 replies; 12+ messages in thread
From: Lancelot SIX @ 2025-06-06 13:36 UTC (permalink / raw)
To: Simon Marchi; +Cc: gdb-patches
On Thu, Jun 05, 2025 at 04:16:27PM -0400, Simon Marchi wrote:
> A following patch will want to call require_forward_progress for a given
> inferior. Extract a new require_forward_progress overload from the
> existing require_forward_progress function that targets a specific
> inferior.
Hi,
This LGTM, thanks.
Approved-by: Lancelot Six <lancelot.six@amd.com> (amdgpu)
Best,
Lancelot.
>
> Change-Id: I54f42b83eb8443d4d91747ffbc86eaeb017f1e49
> ---
> gdb/amd-dbgapi-target.c | 49 +++++++++++++++++++++++------------------
> 1 file changed, 28 insertions(+), 21 deletions(-)
>
> diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
> index 1ec20d1874ec..e86d7f34d0f6 100644
> --- a/gdb/amd-dbgapi-target.c
> +++ b/gdb/amd-dbgapi-target.c
> @@ -443,6 +443,32 @@ async_event_handler_mark ()
> mark_async_event_handler (amd_dbgapi_async_event_handler);
> }
>
> +/* Set forward progress requirement to REQUIRE for inferior INFO. */
> +
> +static void
> +require_forward_progress (amd_dbgapi_inferior_info &info, bool require)
> +{
> + /* If we try to disable forward progress requirement but the target expects
> + resumed threads to be committed to the target, we could wait for events
> + that will never arrive. */
> + if (!require)
> + gdb_assert (!info.inf->process_target ()->commit_resumed_state);
> +
> + gdb_assert (info.process_id != AMD_DBGAPI_PROCESS_NONE);
> +
> + /* Don't do unnecessary calls to amd-dbgapi to avoid polluting the logs. */
> + if (info.forward_progress_required == require)
> + return;
> +
> + const auto progress
> + = require ? AMD_DBGAPI_PROGRESS_NORMAL : AMD_DBGAPI_PROGRESS_NO_FORWARD;
> + const auto status
> + = amd_dbgapi_process_set_progress (info.process_id, progress);
> + gdb_assert (status == AMD_DBGAPI_STATUS_SUCCESS);
> +
> + info.forward_progress_required = require;
> +}
> +
> /* Set forward progress requirement to REQUIRE for all processes of PROC_TARGET
> matching PTID. */
>
> @@ -450,12 +476,6 @@ static void
> require_forward_progress (ptid_t ptid, process_stratum_target *proc_target,
> bool require)
> {
> - /* If we try to disable forward progress requirement but the target expects
> - resumed threads to be committed to the target, we could wait for events
> - that will never arrive. */
> - if (!require)
> - gdb_assert (!proc_target->commit_resumed_state);
> -
> for (inferior *inf : all_inferiors (proc_target))
> {
> if (ptid != minus_one_ptid && inf->pid != ptid.pid ())
> @@ -463,21 +483,8 @@ require_forward_progress (ptid_t ptid, process_stratum_target *proc_target,
>
> amd_dbgapi_inferior_info *info = get_amd_dbgapi_inferior_info (inf);
>
> - if (info->process_id == AMD_DBGAPI_PROCESS_NONE)
> - continue;
> -
> - /* Don't do unnecessary calls to amd-dbgapi to avoid polluting the logs. */
> - if (info->forward_progress_required == require)
> - continue;
> -
> - amd_dbgapi_status_t status
> - = amd_dbgapi_process_set_progress
> - (info->process_id, (require
> - ? AMD_DBGAPI_PROGRESS_NORMAL
> - : AMD_DBGAPI_PROGRESS_NO_FORWARD));
> - gdb_assert (status == AMD_DBGAPI_STATUS_SUCCESS);
> -
> - info->forward_progress_required = require;
> + if (info->process_id != AMD_DBGAPI_PROCESS_NONE)
> + require_forward_progress (*info, require);
>
> /* If ptid targets a single inferior and we have found it, no need to
> continue. */
> --
> 2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 5/5] gdb/amd-dbgapi: disable forward progress requirement in amd_dbgapi_target_breakpoint::check_status
2025-06-05 20:16 ` [PATCH 5/5] gdb/amd-dbgapi: disable forward progress requirement in amd_dbgapi_target_breakpoint::check_status Simon Marchi
@ 2025-06-06 13:58 ` Lancelot SIX
2025-06-09 15:59 ` Simon Marchi
0 siblings, 1 reply; 12+ messages in thread
From: Lancelot SIX @ 2025-06-06 13:58 UTC (permalink / raw)
To: Simon Marchi; +Cc: gdb-patches
On Thu, Jun 05, 2025 at 04:16:28PM -0400, Simon Marchi wrote:
> ROCgdb handles target events very slowly when running a test case like
> this, where a breakpoint is preset on HipTest::vectorADD:
>
> for (int i=0; i < numDevices; ++i) {
> HIPCHECK(hipSetDevice(i));
> hipLaunchKernelGGL(HipTest::vectorADD, dim3(blocks), dim3(threadsPerBlock), 0, stream[i],
> static_cast<const int*>(A_d[i]), static_cast<const int*>(B_d[i]), C_d[i], N);
> }
>
> What happens is:
>
> - A kernel is launched
> - The internal runtime breakpoint is hit during the second
> hipLaunchKernelGGL call, which causes
> amd_dbgapi_target_breakpoint::check_status to be called
> - Meanwhile, all waves of the kernel hit the breakpoint on vectorADD
> - amd_dbgapi_target_breakpoint::check_status calls process_event_queue,
> which pulls the thousand of breakpoint hit events from the kernel
> - As part of handling the breakpoint hit events, we write the PC of the
> waves that stopped to decrement it. Because the forward progress
> requirement is not disabled, this causes a suspend/resume of the
> queue each time, which is time-consuming.
>
> The stack trace where this all happens is:
>
> #32 0x00007ffff6b9abda in amd_dbgapi_write_register (wave_id=..., register_id=..., offset=0, value_size=8, value=0x7fffea9fdcc0) at /home/smarchi/src/amd-dbgapi/src/register.cpp:587
> #33 0x00005555588c0bed in amd_dbgapi_target::store_registers (this=0x55555c7b1d20 <the_amd_dbgapi_target>, regcache=0x507000002240, regno=470) at /home/smarchi/src/wt/amd/gdb/amd-dbgapi-target.c:2504
> #34 0x000055555a5186a1 in target_store_registers (regcache=0x507000002240, regno=470) at /home/smarchi/src/wt/amd/gdb/target.c:3973
> #35 0x0000555559fab831 in regcache::raw_write (this=0x507000002240, regnum=470, src=...) at /home/smarchi/src/wt/amd/gdb/regcache.c:890
> #36 0x0000555559fabd2b in regcache::cooked_write (this=0x507000002240, regnum=470, src=...) at /home/smarchi/src/wt/amd/gdb/regcache.c:915
> #37 0x0000555559fc3ca5 in regcache::cooked_write<unsigned long, void> (this=0x507000002240, regnum=470, val=140737323456768) at /home/smarchi/src/wt/amd/gdb/regcache.c:850
> #38 0x0000555559fab09a in regcache_cooked_write_unsigned (regcache=0x507000002240, regnum=470, val=140737323456768) at /home/smarchi/src/wt/amd/gdb/regcache.c:858
> #39 0x0000555559fb0678 in regcache_write_pc (regcache=0x507000002240, pc=0x7ffff62bd900) at /home/smarchi/src/wt/amd/gdb/regcache.c:1460
> #40 0x00005555588bb37d in process_one_event (event_id=..., event_kind=AMD_DBGAPI_EVENT_KIND_WAVE_STOP) at /home/smarchi/src/wt/amd/gdb/amd-dbgapi-target.c:1873
> #41 0x00005555588bbf7b in process_event_queue (process_id=..., until_event_kind=AMD_DBGAPI_EVENT_KIND_BREAKPOINT_RESUME) at /home/smarchi/src/wt/amd/gdb/amd-dbgapi-target.c:2006
> #42 0x00005555588b1aca in amd_dbgapi_target_breakpoint::check_status (this=0x511000140900, bs=0x50600014ed00) at /home/smarchi/src/wt/amd/gdb/amd-dbgapi-target.c:890
> #43 0x0000555558c50080 in bpstat_stop_status (aspace=0x5070000061b0, bp_addr=0x7fffed0b9ab0, thread=0x518000026c80, ws=..., stop_chain=0x50600014ed00) at /home/smarchi/src/wt/amd/gdb/breakpoint.c:6126
> #44 0x000055555984f4ff in handle_signal_stop (ecs=0x7fffeaa40ef0) at /home/smarchi/src/wt/amd/gdb/infrun.c:7169
> #45 0x000055555984b889 in handle_inferior_event (ecs=0x7fffeaa40ef0) at /home/smarchi/src/wt/amd/gdb/infrun.c:6621
> #46 0x000055555983eab6 in fetch_inferior_event () at /home/smarchi/src/wt/amd/gdb/infrun.c:4750
> #47 0x00005555597caa5f in inferior_event_handler (event_type=INF_REG_EVENT) at /home/smarchi/src/wt/amd/gdb/inf-loop.c:42
> #48 0x00005555588b838e in handle_target_event (client_data=0x0) at /home/smarchi/src/wt/amd/gdb/amd-dbgapi-target.c:1513
>
> Fix that performance problem by disabling the forward progress
> requirement in amd_dbgapi_target_breakpoint::check_status, before
> calling process_event_queue, so that we can process all events
> efficiently.
>
> Since the same performance problem could theoritically happen any time
> process_event_queue is called with forward progress requirement enabled,
> add an assert to ensure that forward progress requirement is disabled
> when process_event_queue is invoked. This makes it necessary to add a
> require_forward_progress call to amd_dbgapi_finalize_core_attach. It
> looks a bit strange, since core files don't have execution, but it
> doesn't hurt.
>
> Add a test that replicates this scenario. The test launches a kernel
> that hits a breakpoint (with an always false condition) repeatedly.
> Meanwhile, the host process loads an unloads a code object, causing
> check_status to be called.
>
> Bug: SWDEV-482511
> Change-Id: Ida86340d679e6bd8462712953458c07ba3fd49ec
Hi Simon,
This looks overall good to me.
> ---
> gdb/amd-dbgapi-target.c | 6 ++
> .../code-object-load-while-breakpoint-hit.cpp | 70 +++++++++++++++++++
> .../code-object-load-while-breakpoint-hit.exp | 68 ++++++++++++++++++
> 3 files changed, 144 insertions(+)
> create mode 100644 gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.cpp
> create mode 100644 gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.exp
>
> diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
> index e86d7f34d0f6..44913bbd7532 100644
> --- a/gdb/amd-dbgapi-target.c
> +++ b/gdb/amd-dbgapi-target.c
> @@ -568,6 +568,8 @@ amd_dbgapi_target_breakpoint::check_status (struct bpstat *bs)
> if (action == AMD_DBGAPI_BREAKPOINT_ACTION_RESUME)
> return;
>
> + require_forward_progress (*info, false);
> +
> /* If the action is AMD_DBGAPI_BREAKPOINT_ACTION_HALT, we need to wait until
> a breakpoint resume event for this breakpoint_id is seen. */
> amd_dbgapi_event_id_t resume_event_id
> @@ -1352,6 +1354,10 @@ static amd_dbgapi_event_id_t
> process_event_queue (amd_dbgapi_inferior_info &info,
> amd_dbgapi_event_kind_t until_event_kind)
> {
> + /* Pulling events with forward progress required may result in bad
> + performance, make sure it is not required. */
> + gdb_assert (!info.forward_progress_required);
> +
> while (true)
> {
> amd_dbgapi_event_id_t event_id;
> diff --git a/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.cpp b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.cpp
> new file mode 100644
> index 000000000000..e97809335569
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.cpp
> @@ -0,0 +1,70 @@
I think you are missing the copyright header for this file.
> +#ifdef DEVICE
> +
> +#include <hip/hip_runtime.h>
> +
> +constexpr unsigned int NUM_BREAKPOINT_HITS = 5;
> +
> +static __device__ void
> +break_here ()
> +{
> + asm ("s_nop 0");
I don't expect this inline asssembly is necessary.
> +}
> +
> +extern "C" __global__ void
> +kernel ()
> +{
> + for (int n = 0; n < NUM_BREAKPOINT_HITS; ++n)
> + break_here ();
> +}
> +
> +#else
> +
> +#include <hip/hip_runtime.h>
> +#include <unistd.h>
> +
> +constexpr unsigned int NUM_ITEMS_PER_BLOCK = 256;
> +constexpr unsigned int NUM_BLOCKS = 128;
> +constexpr unsigned int NUM_ITEMS = NUM_ITEMS_PER_BLOCK * NUM_BLOCKS;
> +constexpr unsigned int NUM_LOAD_UNLOADS = 5;
> +
> +#define CHECK(cmd) \
> + { \
> + hipError_t error = cmd; \
> + if (error != hipSuccess) \
> + { \
> + fprintf (stderr, "error: '%s'(%d) at %s:%d\n", \
> + hipGetErrorString (error), error, __FILE__, __LINE__); \
> + exit (EXIT_FAILURE); \
> + } \
> + }
> +
> +int
> +main (int argc, const char **argv)
> +{
> + if (argc != 2)
> + {
> + fprintf (stderr, "Usage: %s <hip_module_path>\n", argv[0]);
> + return 1;
> + }
> +
> + const auto module_path = argv[1];
> + hipModule_t module;
> + CHECK (hipModuleLoad (&module, module_path));
> +
> + /* Launch the kernel. */
> + hipFunction_t function;
> + CHECK (hipModuleGetFunction (&function, module, "kernel"));
> + CHECK (hipModuleLaunchKernel (function, NUM_BLOCKS, 1, 1,
> + NUM_ITEMS_PER_BLOCK, 1, 1, 0, nullptr, nullptr,
> + nullptr));
> +
> + /* Load and unload the module many times. */
> + for (int i = 0; i < NUM_LOAD_UNLOADS; ++i)
> + {
> + hipModule_t dummy_module;
> + CHECK (hipModuleLoad (&dummy_module, module_path));
> + CHECK (hipModuleUnload (dummy_module));
> + }
> +}
> +
> +#endif
> diff --git a/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.exp b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.exp
> new file mode 100644
> index 000000000000..b8d003f37032
> --- /dev/null
> +++ b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.exp
> @@ -0,0 +1,68 @@
> +# Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
The copyright should be to the FSF, not AMD.
Given the elements above are fixed,
Approved-by: Lancelot Six <lancelot.six@amd.com> (amdgpu)
Best,
Lanecelot.
> +
> +# This file is part of GDB.
> +
> +# 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; either version 3 of the License, or
> +# (at your option) any later version.
> +
> +# 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, see <http://www.gnu.org/licenses/>.
> +
> +# This test verifies what happens when a code object list update happens at the
> +# same time as some wave stop events are reported. It was added following a
> +# performance bug fix, where forward progress requirement disabled when
> +# pulling events from amd-dbgapi in amd_dbgapi_target_breakpoint::check_status.
> +#
> +# The test launches a kernel that hits a breakpoint with an always false
> +# condition a certain number of times. Meanwhile, the host loads and unloads
> +# a code object in a loop, causing check_status to be called. The hope is that
> +# check_status, when calling process_event_queue, will pull many WAVE_STOP
> +# events from the kernel hitting the breakpoint.
> +#
> +# Without the appropriate fix (of disabling forward progress requirement in
> +# check_status), GDB would hit the newly-added assert in process_event_queue,
> +# which verifies that forward progress requirement is disabled. Even without
> +# this assert, the test would likely time out (depending on the actual timeout
> +# value).
> +
> +load_lib rocm.exp
> +standard_testfile .cpp
> +require allow_hipcc_tests
> +
> +# Build the host executable.
> +if { [build_executable "failed to prepare" \
> + $testfile $srcfile {debug hip}] == -1 } {
> + return -1
> +}
> +
> +set hipmodule_path [standard_output_file ${testfile}.co]
> +
> +# Build the kernel object file.
> +if { [gdb_compile $srcdir/$subdir/$srcfile \
> + $hipmodule_path object \
> + { debug hip additional_flags=--genco additional_flags=-DDEVICE } ] != "" } {
> + return -1
> +}
> +
> +proc do_test { } {
> + with_rocm_gpu_lock {
> + clean_restart $::binfile
> + gdb_test_no_output "set args $::hipmodule_path" "set args"
> +
> + if { ![runto_main] } {
> + return
> + }
> +
> + gdb_test "with breakpoint pending on -- break break_here if 0"
> + gdb_continue_to_end "continue to end" "continue" 1
> + }
> +}
> +
> +do_test
> --
> 2.49.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 3/5] gdb/amd-dbgapi: pass amd_dbgapi_inferior_info to process_event_queue
2025-06-06 11:00 ` Lancelot SIX
@ 2025-06-09 15:36 ` Simon Marchi
0 siblings, 0 replies; 12+ messages in thread
From: Simon Marchi @ 2025-06-09 15:36 UTC (permalink / raw)
To: Lancelot SIX, Simon Marchi; +Cc: gdb-patches
On 6/6/25 7:00 AM, Lancelot SIX wrote:
> On Thu, Jun 05, 2025 at 04:16:26PM -0400, Simon Marchi wrote:
>> A following patch will make process_event_queue access a field of
>> amd_dbgapi_inferior_info. Prepare for this by making
>> process_event_queue accept an amd_dbgapi_inferior_info object, instead
>> of a process id.
>>
>> Change-Id: I9adc491dd1ff64ff74c40aa7662fffb11bd8332b
>> ---
>> gdb/amd-dbgapi-target.c | 25 +++++++++----------------
>> 1 file changed, 9 insertions(+), 16 deletions(-)
>>
>> diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
>> index 8fd8bcf5ae49..1ec20d1874ec 100644
>> --- a/gdb/amd-dbgapi-target.c
>> +++ b/gdb/amd-dbgapi-target.c
>> @@ -234,7 +234,7 @@ struct amd_dbgapi_inferior_info
>> };
>>
>> static amd_dbgapi_event_id_t process_event_queue
>> - (amd_dbgapi_process_id_t process_id,
>> + (amd_dbgapi_inferior_info &info,
>> amd_dbgapi_event_kind_t until_event_kind = AMD_DBGAPI_EVENT_KIND_NONE);
>>
>> static const target_info amd_dbgapi_target_info = {
>> @@ -564,8 +564,7 @@ amd_dbgapi_target_breakpoint::check_status (struct bpstat *bs)
>> /* If the action is AMD_DBGAPI_BREAKPOINT_ACTION_HALT, we need to wait until
>> a breakpoint resume event for this breakpoint_id is seen. */
>> amd_dbgapi_event_id_t resume_event_id
>> - = process_event_queue (info->process_id,
>> - AMD_DBGAPI_EVENT_KIND_BREAKPOINT_RESUME);
>> + = process_event_queue (*info, AMD_DBGAPI_EVENT_KIND_BREAKPOINT_RESUME);
>>
>> /* We should always get a breakpoint_resume event after processing all
>> events generated by reporting the breakpoint hit. */
>> @@ -1337,28 +1336,22 @@ event_kind_str (amd_dbgapi_event_kind_t kind)
>> gdb_assert_not_reached ("unhandled amd_dbgapi_event_kind_t value");
>> }
>>
>> -/* Drain the dbgapi event queue of a given process_id, or of all processes if
>> - process_id is AMD_DBGAPI_PROCESS_NONE. Stop processing the events if an
>> - event of a given kind is requested and `process_id` is not
>> - AMD_DBGAPI_PROCESS_NONE. Wave stop events that are not returned are queued
>> - into their inferior's amd_dbgapi_inferior_info pending wave events. */
>> +/* Drain the dbgapi event queue of a given process_id. Stop processing the
>
> It reads odd to have process_id here, as we don't pass it as an explicit
> parameter anymore. Could it say "a given inferior" instead?
Yes, makes sense.
>
>> + events if an event of a given kind is requested (not AMD_DBGAPI_EVENT_NONE).
>> + Wave stop events that are not returned are queued into their inferior's
>> + amd_dbgapi_inferior_info pending wave events. */
>
> My first intuition when reading this patch was "hey, the INFO param is
> never modified, why not use a const ref". But eventually ,under
> process_one_event, we'll grab a reference to the INFO and modify it to
> stash stop events.
>
> Should this patch go one step further, and have the INFO passed to
> process_one_event (this one can ensure the event's process_id matches
> the INFO's process_id)? This would also save iterating over all
> inferiors to find the one we are looking for.
Oh, yes, that's a good idea. Or, we could just skip the
AMD_DBGAPI_EVENT_INFO_PROCESS and AMD_DBGAPI_PROCESS_INFO_OS_ID calls
altogether, since we know for which process the event is anyway. I will
add this as a separate patch just after this one.
Simon
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 5/5] gdb/amd-dbgapi: disable forward progress requirement in amd_dbgapi_target_breakpoint::check_status
2025-06-06 13:58 ` Lancelot SIX
@ 2025-06-09 15:59 ` Simon Marchi
0 siblings, 0 replies; 12+ messages in thread
From: Simon Marchi @ 2025-06-09 15:59 UTC (permalink / raw)
To: Lancelot SIX, Simon Marchi; +Cc: gdb-patches
>> diff --git a/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.cpp b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.cpp
>> new file mode 100644
>> index 000000000000..e97809335569
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.cpp
>> @@ -0,0 +1,70 @@
>
> I think you are missing the copyright header for this file.
Done.
>> +#ifdef DEVICE
>> +
>> +#include <hip/hip_runtime.h>
>> +
>> +constexpr unsigned int NUM_BREAKPOINT_HITS = 5;
>> +
>> +static __device__ void
>> +break_here ()
>> +{
>> + asm ("s_nop 0");
>
> I don't expect this inline asssembly is necessary.
Ok, will remove it. Not sure why I added it, I might have had some
trouble with empty functions in the past.
>> diff --git a/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.exp b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.exp
>> new file mode 100644
>> index 000000000000..b8d003f37032
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.rocm/code-object-load-while-breakpoint-hit.exp
>> @@ -0,0 +1,68 @@
>> +# Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
>
> The copyright should be to the FSF, not AMD.
Done.
> Given the elements above are fixed,
>
> Approved-by: Lancelot Six <lancelot.six@amd.com> (amdgpu)
Thanks,
Simon
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-06-09 16:00 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-06-05 20:16 [PATCH 1/5] gdb/amd-dbgapi: remove unnecessary AMD_DBGAPI_EVENT_KIND_NONE argument Simon Marchi
2025-06-05 20:16 ` [PATCH 2/5] gdb/amd-dbgapi: add assert in require_forward_progress Simon Marchi
2025-06-06 10:06 ` Lancelot SIX
2025-06-05 20:16 ` [PATCH 3/5] gdb/amd-dbgapi: pass amd_dbgapi_inferior_info to process_event_queue Simon Marchi
2025-06-06 11:00 ` Lancelot SIX
2025-06-09 15:36 ` Simon Marchi
2025-06-05 20:16 ` [PATCH 4/5] gdb/amd-dbgapi: factor out require_forward_progress overload to target one inferior Simon Marchi
2025-06-06 13:36 ` Lancelot SIX
2025-06-05 20:16 ` [PATCH 5/5] gdb/amd-dbgapi: disable forward progress requirement in amd_dbgapi_target_breakpoint::check_status Simon Marchi
2025-06-06 13:58 ` Lancelot SIX
2025-06-09 15:59 ` Simon Marchi
2025-06-06 9:59 ` [PATCH 1/5] gdb/amd-dbgapi: remove unnecessary AMD_DBGAPI_EVENT_KIND_NONE argument Lancelot SIX
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox