diff options
-rw-r--r-- | gdb/amd-dbgapi-target.c | 194 |
1 files changed, 153 insertions, 41 deletions
diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c index be5e9ff..9aa8db2 100644 --- a/gdb/amd-dbgapi-target.c +++ b/gdb/amd-dbgapi-target.c @@ -109,10 +109,9 @@ get_amd_dbgapi_target_inferior_created_observer_token () return amd_dbgapi_target_inferior_created_observer_token; } -/* A type holding coordinate, etc. info for a given wave. We cache - this because we need this information after a wave exits. */ +/* A type holding coordinates, etc. info for a given wave. */ -struct wave_info +struct wave_coordinates { /* The wave. Set by the ctor. */ amd_dbgapi_wave_id_t wave_id; @@ -125,13 +124,44 @@ struct wave_info uint32_t group_ids[3] {UINT32_MAX, UINT32_MAX, UINT32_MAX}; uint32_t wave_in_group = UINT32_MAX; - explicit wave_info (amd_dbgapi_wave_id_t wave_id) + explicit wave_coordinates (amd_dbgapi_wave_id_t wave_id) : wave_id (wave_id) {} - /* Return the target ID string for the wave this wave_info is + /* Return the target ID string for the wave this wave_coordinates is for. */ std::string to_string () const; + + /* Pull out coordinates info from the amd-dbgapi library. */ + void fetch (); +}; + +/* A type holding info about a given wave. */ + +struct wave_info +{ + /* We cache the coordinates info because we need it after a wave + exits. The wave's ID is here. */ + wave_coordinates coords; + + /* The last resume_mode passed to amd_dbgapi_wave_resume for this + wave. We track this because we are guaranteed to see a + WAVE_COMMAND_TERMINATED event if a stepping wave terminates, and + we need to know to not delete such a wave until we process that + event. */ + amd_dbgapi_resume_mode_t last_resume_mode = AMD_DBGAPI_RESUME_MODE_NORMAL; + + /* Whether we've called amd_dbgapi_wave_stop for this wave and are + waiting for its stop event. Similarly, we track this because + we're guaranteed to get a WAVE_COMMAND_TERMINATED event if the + wave terminates while being stopped. */ + bool stopping = false; + + explicit wave_info (amd_dbgapi_wave_id_t wave_id) + : coords (wave_id) + { + coords.fetch (); + } }; /* Big enough to hold the size of the largest register in bytes. */ @@ -277,6 +307,19 @@ static struct amd_dbgapi_target the_amd_dbgapi_target; static const registry<inferior>::key<amd_dbgapi_inferior_info> amd_dbgapi_inferior_data; +/* Fetch the amd_dbgapi_inferior_info data for the given inferior. */ + +static struct amd_dbgapi_inferior_info * +get_amd_dbgapi_inferior_info (struct inferior *inferior) +{ + amd_dbgapi_inferior_info *info = amd_dbgapi_inferior_data.get (inferior); + + if (info == nullptr) + info = amd_dbgapi_inferior_data.emplace (inferior, inferior); + + return info; +} + /* The async event handler registered with the event loop, indicating that we might have events to report to the core and that we'd like our wait method to be called. @@ -291,7 +334,7 @@ static const registry<inferior>::key<amd_dbgapi_inferior_info> static async_event_handler *amd_dbgapi_async_event_handler = nullptr; std::string -wave_info::to_string () const +wave_coordinates::to_string () const { std::string str = "AMDGPU Wave"; @@ -323,30 +366,41 @@ wave_info::to_string () const /* Read in wave_info for WAVE_ID. */ -static wave_info -get_wave_info (amd_dbgapi_wave_id_t wave_id) +void +wave_coordinates::fetch () { - wave_info res (wave_id); - /* Any field that fails to be read is left with its in-class initialized value, which is printed as "?". */ amd_dbgapi_wave_get_info (wave_id, AMD_DBGAPI_WAVE_INFO_AGENT, - sizeof (res.agent_id), &res.agent_id); + sizeof (agent_id), &agent_id); amd_dbgapi_wave_get_info (wave_id, AMD_DBGAPI_WAVE_INFO_QUEUE, - sizeof (res.queue_id), &res.queue_id); + sizeof (queue_id), &queue_id); amd_dbgapi_wave_get_info (wave_id, AMD_DBGAPI_WAVE_INFO_DISPATCH, - sizeof (res.dispatch_id), &res.dispatch_id); + sizeof (dispatch_id), &dispatch_id); amd_dbgapi_wave_get_info (wave_id, AMD_DBGAPI_WAVE_INFO_WORKGROUP_COORD, - sizeof (res.group_ids), &res.group_ids); + sizeof (group_ids), &group_ids); amd_dbgapi_wave_get_info (wave_id, AMD_DBGAPI_WAVE_INFO_WAVE_NUMBER_IN_WORKGROUP, - sizeof (res.wave_in_group), &res.wave_in_group); + sizeof (wave_in_group), &wave_in_group); +} - return res; +/* Get the wave_info object for TP, from the wave_info map. It is + assumed that the wave is in the map. */ + +static wave_info & +get_thread_wave_info (thread_info *tp) +{ + amd_dbgapi_inferior_info *info = get_amd_dbgapi_inferior_info (tp->inf); + amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (tp->ptid); + + auto it = info->wave_info_map.find (wave_id.handle); + gdb_assert (it != info->wave_info_map.end ()); + + return it->second; } /* Clear our async event handler. */ @@ -367,19 +421,6 @@ async_event_handler_mark () mark_async_event_handler (amd_dbgapi_async_event_handler); } -/* Fetch the amd_dbgapi_inferior_info data for the given inferior. */ - -static struct amd_dbgapi_inferior_info * -get_amd_dbgapi_inferior_info (struct inferior *inferior) -{ - amd_dbgapi_inferior_info *info = amd_dbgapi_inferior_data.get (inferior); - - if (info == nullptr) - info = amd_dbgapi_inferior_data.emplace (inferior, inferior); - - return info; -} - /* Set forward progress requirement to REQUIRE for all processes of PROC_TARGET matching PTID. */ @@ -562,12 +603,12 @@ amd_dbgapi_target::pid_to_str (ptid_t ptid) auto it = info->wave_info_map.find (wave_id.handle); if (it != info->wave_info_map.end ()) - return it->second.to_string (); + return it->second.coords.to_string (); /* A wave we don't know about. Shouldn't usually happen, but asserting and bringing down the session is a bit too harsh. Just print all unknown info as "?"s. */ - return wave_info (wave_id).to_string (); + return wave_coordinates (wave_id).to_string (); } const char * @@ -691,16 +732,24 @@ amd_dbgapi_target::resume (ptid_t scope_ptid, int step, enum gdb_signal signo) amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (thread->ptid); amd_dbgapi_status_t status; + + wave_info &wi = get_thread_wave_info (thread); + amd_dbgapi_resume_mode_t &resume_mode = wi.last_resume_mode; + amd_dbgapi_exceptions_t wave_exception; if (thread->ptid == inferior_ptid) - status = amd_dbgapi_wave_resume (wave_id, - (step - ? AMD_DBGAPI_RESUME_MODE_SINGLE_STEP - : AMD_DBGAPI_RESUME_MODE_NORMAL), - exception); + { + resume_mode = (step + ? AMD_DBGAPI_RESUME_MODE_SINGLE_STEP + : AMD_DBGAPI_RESUME_MODE_NORMAL); + wave_exception = exception; + } else - status = amd_dbgapi_wave_resume (wave_id, AMD_DBGAPI_RESUME_MODE_NORMAL, - AMD_DBGAPI_EXCEPTION_NONE); + { + resume_mode = AMD_DBGAPI_RESUME_MODE_NORMAL; + wave_exception = AMD_DBGAPI_EXCEPTION_NONE; + } + status = amd_dbgapi_wave_resume (wave_id, resume_mode, wave_exception); if (status != AMD_DBGAPI_STATUS_SUCCESS /* Ignore the error that wave is no longer valid as that could indicate that the process has exited. GDB treats resuming a @@ -708,6 +757,8 @@ amd_dbgapi_target::resume (ptid_t scope_ptid, int step, enum gdb_signal signo) && status != AMD_DBGAPI_STATUS_ERROR_INVALID_WAVE_ID) error (_("wave_resume for wave_%ld failed (%s)"), wave_id.handle, get_status_string (status)); + + wi.stopping = false; } } @@ -722,6 +773,21 @@ amd_dbgapi_target::commit_resumed () require_forward_progress (minus_one_ptid, proc_target, true); } +/* Return a string version of RESUME_MODE, for debug log purposes. */ + +static const char * +resume_mode_to_string (amd_dbgapi_resume_mode_t resume_mode) +{ + switch (resume_mode) + { + case AMD_DBGAPI_RESUME_MODE_NORMAL: + return "normal"; + case AMD_DBGAPI_RESUME_MODE_SINGLE_STEP: + return "step"; + } + gdb_assert_not_reached ("invalid amd_dbgapi_resume_mode_t"); +} + void amd_dbgapi_target::stop (ptid_t ptid) { @@ -755,7 +821,11 @@ amd_dbgapi_target::stop (ptid_t ptid) status = amd_dbgapi_wave_stop (wave_id); if (status == AMD_DBGAPI_STATUS_SUCCESS) - return; + { + wave_info &wi = get_thread_wave_info (thread); + wi.stopping = true; + return; + } if (status != AMD_DBGAPI_STATUS_ERROR_INVALID_WAVE_ID) error (_("wave_stop for wave_%ld failed (%s)"), wave_id.handle, @@ -769,6 +839,23 @@ amd_dbgapi_target::stop (ptid_t ptid) could have terminated since the last time the wave list was refreshed. */ + wave_info &wi = get_thread_wave_info (thread); + wi.stopping = true; + + amd_dbgapi_debug_printf ("got AMD_DBGAPI_STATUS_ERROR_INVALID_WAVE_ID " + "for wave_%ld, last_resume_mode=%s, " + "report_thread_events=%d", + wave_id.handle, + resume_mode_to_string (wi.last_resume_mode), + m_report_thread_events); + + /* If the wave was stepping when it terminated, then it is + guaranteed that we will see a WAVE_COMMAND_TERMINATED event + for it. Don't report a thread exit event or delete the + thread yet, until we see such event. */ + if (wi.last_resume_mode == AMD_DBGAPI_RESUME_MODE_SINGLE_STEP) + return; + if (m_report_thread_events) { get_amd_dbgapi_inferior_info (thread->inf)->wave_events.emplace_back @@ -1015,7 +1102,7 @@ add_gpu_thread (inferior *inf, ptid_t wave_ptid) auto wave_id = get_amd_dbgapi_wave_id (wave_ptid); if (!info->wave_info_map.try_emplace (wave_id.handle, - get_wave_info (wave_id)).second) + wave_info (wave_id)).second) internal_error ("wave ID %ld already in map", wave_id.handle); /* Create new GPU threads silently to avoid spamming the terminal @@ -1767,7 +1854,32 @@ amd_dbgapi_target::update_thread_list () auto it = threads.find (tp->ptid.tid ()); if (it == threads.end ()) - delete_thread_silent (tp); + { + auto wave_id = get_amd_dbgapi_wave_id (tp->ptid); + wave_info &wi = get_thread_wave_info (tp); + + /* Waves that were stepping or in progress of being + stopped are guaranteed to report a + WAVE_COMMAND_TERMINATED event if they terminate. + Don't delete such threads until we see the + event. */ + if (wi.last_resume_mode == AMD_DBGAPI_RESUME_MODE_SINGLE_STEP + || wi.stopping) + { + amd_dbgapi_debug_printf + ("wave_%ld disappeared, keeping it" + " (last_resume_mode=%s, stopping=%d)", + wave_id.handle, + resume_mode_to_string (wi.last_resume_mode), + wi.stopping); + } + else + { + amd_dbgapi_debug_printf ("wave_%ld disappeared, deleting it", + wave_id.handle); + delete_thread_silent (tp); + } + } else threads.erase (it); } |