Skip to content

WIP: lane debugging support #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 55 commits into
base: users/palves/amd-staging-without-lane-support
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
defa7f9
Add wave_get_info/wave_get_info_throw/dispatch_get_info_throw wrappers
palves Sep 3, 2020
00b0cb7
Introduce gdbarch_active_lanes_mask
palves Sep 3, 2020
d5ac022
Introduce gdbarch_supported_lanes_count (hardware lanes)
palves Sep 3, 2020
aa5d9a7
Introduce gdbarch_used_lanes_count (partial work-groups)
palves Oct 4, 2020
67ba0de
Introduce target_lane_to_str
palves Oct 9, 2020
b18b1ff
Introduce "maint set lane-divergence-support"
palves Jul 21, 2021
220e564
Base lane debugging support
palves Sep 3, 2020
411cd1b
Add "info lanes" & "lane" commands
palves Aug 15, 2021
30ff747
Add "lane apply" command
palves Aug 15, 2021
fc59b01
Make "thread find" hit lane target IDs as well
palves Oct 16, 2020
edefe5c
Implement $_lane and $_lane_count convenience vars
palves Oct 16, 2020
f85901b
Implement $_lane_workgroup_pos/$_thread_workgroup_pos convenience vars
palves Oct 16, 2020
f1cb678
Automatically step over divergent regions
palves Oct 27, 2020
bf8a4ca
Implement support for DW_OP_LLVM_push_lane
palves Jun 29, 2021
c0f3032
Implement $_dispatch_pos convenience var
palves Oct 17, 2020
f94f2cf
Base lane debugging tests
palves Sep 4, 2020
cb20964
MI: Handle global "--lane" switch
palves Jan 6, 2022
59b316b
MI: account for lane changes
palves Mar 21, 2025
40ab97f
MI: Make *stopped print "lane-id" and "hit-lanes"
palves Jan 6, 2022
ac95e2a
MI: Make the varobj code aware of lanes
palves Jan 6, 2022
0f261b8
varobj: switch to the right context before fetching lazy value
palves Jan 14, 2022
1aef17a
MI: -thread-select -l LANE
palves Jan 7, 2022
9fc4fd3
MI: Emit lane-id in -thread-select response
palves Jan 7, 2022
9b4fde8
MI: Emit lane-id in =thread-selected
palves Jan 7, 2022
0f4d07c
MI: New -lane-info command
palves Jan 7, 2022
9dc883a
MI lane tests
palves Jan 18, 2022
d2e6094
Document MI lane support
palves Jan 19, 2022
e867e57
Flush dcache if lane changes
palves Aug 26, 2021
0f9dd2b
HACK: Restore per-lane "finish" support
palves Mar 21, 2025
e2c8dba
HACK: Restore lane watchpoints supports
palves Mar 21, 2025
aa80da4
HACK: MI: restore lane-id on memory change notifications
palves Mar 21, 2025
cd2736b
HACK: restore DWARF lanes support
palves Mar 21, 2025
cfcb276
Tests for lane improvements meetings
palves Apr 3, 2025
57f8ba4
Introduce bp_specificity
palves Feb 6, 2025
536d584
Make describe_other_breakpoints static
palves Apr 4, 2025
5db2e6a
describe_other_breakpoints handle all bp specificities
palves Apr 4, 2025
de80b91
Make gdb.Breakpoint __repr__ handle inferior-specific bps
palves Feb 6, 2025
293f13a
get_positive_number_trailer -> get_non_negative_number_trailer
palves Feb 6, 2025
0a4963a
Make get_number_trailer return std::optional<int>
palves Feb 6, 2025
bc5a9f5
lane INF.THR.LANE
palves Mar 4, 2025
1a31f5e
break foo lane [[INF.]THR.]L
palves Apr 4, 2025
3368ee2
Make "info lanes / lane apply" walk all lanes & handle fully-qualifie…
palves Apr 4, 2025
1b3091f
"thread apply" should preserve each thread's lane
palves Mar 6, 2025
fb8bfc8
"thread" / "lane" command's output
palves Mar 6, 2025
7e65a49
Make "info lanes" and "lane apply" options additive & add "-unused" o…
palves Mar 19, 2025
3a5a890
"info threads" current-lane column
palves Mar 19, 2025
dd5b636
Move "info threads"'s "current lane" column
palves Mar 19, 2025
2c0830d
Remove "Current lane is inactive" warning
palves Mar 31, 2025
be24283
Replace inactive lane warning with printing " = <lane inactive>".
palves Mar 31, 2025
8106997
Print frame if lane is inactive
palves Apr 2, 2025
4d493bc
Revert 'Make "thread find" hit lane target IDs as well'
palves Apr 2, 2025
df69e8f
Introduce "lane find" command
palves Apr 2, 2025
0d121b0
Introduce var_expression options/commands
palves Apr 3, 2025
0bbaf51
"info lanes -if EXPR" and "lane apply -if EXPR"
palves Apr 3, 2025
1140b0b
"info threads -if EXPR" and "thread apply -if EXPR"
palves Apr 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions gdb/ada-tasks.c
Original file line number Diff line number Diff line change
Expand Up @@ -1583,8 +1583,8 @@ task_apply_all_command (const char *cmd, int from_tty)

for (const auto &info : thr_list_cpy)
if (switch_to_thread_if_alive (info.second.get ()))
thread_try_catch_cmd (info.second.get (), info.first, cmd,
from_tty, flags);
thr_lane_try_catch_cmd (false, info.second.get (), 0, info.first, cmd,
from_tty, flags);
}

/* Implementation of 'task apply'. */
Expand Down Expand Up @@ -1647,8 +1647,8 @@ task_apply_command (const char *tidlist, int from_tty)

for (const auto &info : thr_list_cpy)
if (switch_to_thread_if_alive (info.second.get ()))
thread_try_catch_cmd (info.second.get (), info.first, cmd,
from_tty, flags);
thr_lane_try_catch_cmd (false, info.second.get (), 0, info.first, cmd,
from_tty, flags);
}

void _initialize_tasks ();
Expand Down
251 changes: 249 additions & 2 deletions gdb/amd-dbgapi-target.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,12 @@ struct amd_dbgapi_target final : public target_ops

std::string pid_to_str (ptid_t ptid) override;

std::string lane_to_str (thread_info *thr, int lane) override;

std::string dispatch_pos_str (thread_info *thr) override;
std::string thread_workgroup_pos_str (thread_info *thr) override;
std::string lane_workgroup_pos_str (thread_info *thr, int lane) override;

const char *thread_name (thread_info *tp) override;

const char *extra_thread_info (thread_info *tp) override;
Expand Down Expand Up @@ -507,6 +513,25 @@ dispatch_target_id_string (amd_dbgapi_dispatch_id_t dispatch_id)
os_id);
}

/* Return the dispatch position string for a given thread. */

static std::string
dispatch_pos_string (thread_info *tp)
{
uint32_t group_ids[3];
if (wave_get_info (tp, AMD_DBGAPI_WAVE_INFO_WORKGROUP_COORD, group_ids)
!= AMD_DBGAPI_STATUS_SUCCESS)
return "(?,?,?)/?";

uint32_t wave_in_group;
wave_get_info_throw (tp, AMD_DBGAPI_WAVE_INFO_WAVE_NUMBER_IN_WORKGROUP,
wave_in_group);

return string_printf ("(%d,%d,%d)/%d",
group_ids[0], group_ids[1], group_ids[2],
wave_in_group);
}

/* Return the target id string for a given queue. */
static std::string
queue_target_id_string (amd_dbgapi_queue_id_t queue_id)
Expand Down Expand Up @@ -548,6 +573,187 @@ agent_target_id_string (amd_dbgapi_agent_id_t agent_id)
return string_printf ("AMDGPU Agent (GPUID %ld)", os_id);
}

/* Return the thread/wave's workgroup position as a string. */

static std::string
thread_workgroup_pos_string (thread_info *tp)
{
uint32_t wave_in_group;
if (wave_get_info (tp, AMD_DBGAPI_WAVE_INFO_WAVE_NUMBER_IN_WORKGROUP,
wave_in_group) != AMD_DBGAPI_STATUS_SUCCESS)
return "?";

return string_printf ("%u", wave_in_group);
}

/* Convert flat ID FLATID to coordinates and store them in COORD_ID.
SIZES is the sizes of each axis. */

static void
flatid_to_id (uint32_t coord_id[3], size_t flatid, const size_t sizes[3])
{
coord_id[2] = flatid / (sizes[0] * sizes[1]);

flatid -= (size_t) coord_id[2] * sizes[0] * sizes[1];

coord_id[1] = flatid / sizes[0];

flatid -= (size_t) coord_id[1] * sizes[0];

coord_id[0] = flatid;
}

/* Object used to collect information about a work-item. Used to
compute work-item coordinates taking into account partial
work-groups. */

struct work_item_info
{
amd_dbgapi_dispatch_id_t dispatch_id;
amd_dbgapi_queue_id_t queue_id;
amd_dbgapi_agent_id_t agent_id;

/* Grid sizes in work-items. */
uint32_t grid_sizes[3];

/* Grid's work-group sizes in work-items. */
uint16_t work_group_sizes[3];

/* Grid work-group coordinates. */
uint32_t work_group_ids[3];

/* Wave in work-group. */
uint32_t wave_in_group;

/* Lane count per wave. */
size_t lane_count;

/* Return the flat work-item id of the lane at index LANE_INDEX. */
size_t flatid (int lane_index) const
{
return wave_in_group * lane_count + lane_index;
}

/* Store in PARTIAL_WORKGROUP_SIZES the work-group item sizes for
each axis, taking into account the work-items that actually fit
in the grid. */
void partial_work_group_sizes (size_t partial_work_group_sizes[3]) const
{
for (int i = 0; i < 3; i++)
{
size_t work_item_start = work_group_ids[i] * work_group_sizes[i];
size_t work_item_end = work_item_start + work_group_sizes[i];
if (work_item_end > grid_sizes[i])
work_item_end = grid_sizes[i];
partial_work_group_sizes[i] = work_item_end - work_item_start;
}
}
};

/* Populate WI, a work_item_info object describing lane LANE of wave
TP. Returns true on success, false if info is not available. */

static bool
make_work_item_info (thread_info *tp, int lane, work_item_info *wi)
{
if (wave_get_info (tp, AMD_DBGAPI_WAVE_INFO_DISPATCH, wi->dispatch_id)
!= AMD_DBGAPI_STATUS_SUCCESS)
{
/* The dispatch associated with a wave is not available. A wave
may not have an associated dispatch if attaching to a process
with already existing waves. */
return false;
}

wave_get_info_throw (tp, AMD_DBGAPI_WAVE_INFO_QUEUE, wi->queue_id);
wave_get_info_throw (tp, AMD_DBGAPI_WAVE_INFO_AGENT, wi->agent_id);
dispatch_get_info_throw (wi->dispatch_id, AMD_DBGAPI_DISPATCH_INFO_GRID_SIZES,
wi->grid_sizes);

dispatch_get_info_throw (wi->dispatch_id,
AMD_DBGAPI_DISPATCH_INFO_WORKGROUP_SIZES,
wi->work_group_sizes);

wave_get_info_throw (tp, AMD_DBGAPI_WAVE_INFO_WORKGROUP_COORD,
wi->work_group_ids);

wave_get_info_throw (tp, AMD_DBGAPI_WAVE_INFO_WAVE_NUMBER_IN_WORKGROUP,
wi->wave_in_group);

wave_get_info_throw (tp, AMD_DBGAPI_WAVE_INFO_LANE_COUNT, wi->lane_count);

return true;
}

/* Return the lane's work-group position as a string. */

static std::string
lane_workgroup_pos_string (thread_info *tp, int lane)
{
work_item_info wi;

if (make_work_item_info (tp, lane, &wi))
{
size_t partial_work_group_sizes[3];

wi.partial_work_group_sizes (partial_work_group_sizes);

size_t work_item_flatid = wi.flatid (lane);

uint32_t work_item_ids[3];
flatid_to_id (work_item_ids, work_item_flatid, partial_work_group_sizes);

return string_printf ("[%d,%d,%d]",
work_item_ids[0], work_item_ids[1], work_item_ids[2]);
}
else
return "[?,?,?]";
}

/* Return the target id string for a given lane. */

static std::string
lane_target_id_string (thread_info *tp, int lane)
{
amd_dbgapi_dispatch_id_t dispatch_id;
amd_dbgapi_queue_id_t queue_id;
amd_dbgapi_agent_id_t agent_id;
uint32_t group_ids[3];

std::string str = "AMDGPU Lane ";

str += (wave_get_info (tp, AMD_DBGAPI_WAVE_INFO_AGENT, agent_id)
== AMD_DBGAPI_STATUS_SUCCESS)
? string_printf ("%ld", agent_id.handle)
: " ?";

str += (wave_get_info (tp, AMD_DBGAPI_WAVE_INFO_QUEUE, queue_id)
== AMD_DBGAPI_STATUS_SUCCESS)
? string_printf (":%ld", queue_id.handle)
: ":?";

str += (wave_get_info (tp, AMD_DBGAPI_WAVE_INFO_DISPATCH,
dispatch_id)
== AMD_DBGAPI_STATUS_SUCCESS)
? string_printf (":%ld", dispatch_id.handle)
: ":?";

amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (tp->ptid);

str += string_printf (":%ld/%d", wave_id.handle, lane);

str += (wave_get_info (tp, AMD_DBGAPI_WAVE_INFO_WORKGROUP_COORD,
group_ids)
== AMD_DBGAPI_STATUS_SUCCESS
? string_printf (" (%d,%d,%d)", group_ids[0], group_ids[1],
group_ids[2])
: " (?,?,?)");

str += lane_workgroup_pos_string (tp, lane);

return str;
}

/* Clear our async event handler. */

static void
Expand Down Expand Up @@ -788,6 +994,46 @@ amd_dbgapi_target::pid_to_str (ptid_t ptid)
return wave_coordinates (wave_id).to_string ();
}

std::string
amd_dbgapi_target::lane_to_str (thread_info *thr, int lane)
{
if (!ptid_is_gpu (thr->ptid))
return beneath ()->lane_to_str (thr, lane);

return lane_target_id_string (thr, lane);
}

/* Implementation of target_workgroup_pos_str. */

std::string
amd_dbgapi_target::dispatch_pos_str (thread_info *thr)
{
if (!ptid_is_gpu (thr->ptid))
return beneath ()->dispatch_pos_str (thr);

return dispatch_pos_string (thr);
}

std::string
amd_dbgapi_target::thread_workgroup_pos_str (thread_info *thr)
{
if (!ptid_is_gpu (thr->ptid))
return beneath ()->thread_workgroup_pos_str (thr);

return thread_workgroup_pos_string (thr);
}

/* Implementation of target_lane_workgroup_pos_str. */

std::string
amd_dbgapi_target::lane_workgroup_pos_str (thread_info *thr, int lane)
{
if (!ptid_is_gpu (thr->ptid))
return beneath ()->lane_workgroup_pos_str (thr, lane);

return lane_workgroup_pos_string (thr, lane);
}

const char *
amd_dbgapi_target::extra_thread_info (thread_info *tp)
{
Expand Down Expand Up @@ -840,13 +1086,14 @@ amd_dbgapi_target::xfer_partial (enum target_object object, const char *annex,

size_t len = requested_len;
amd_dbgapi_status_t status;
int current_lane = inferior_thread ()->current_simd_lane ();

if (readbuf != nullptr)
status = amd_dbgapi_read_memory (process_id, wave_id, 0,
status = amd_dbgapi_read_memory (process_id, wave_id, current_lane,
address_space_id, segment_address, &len,
readbuf);
else
status = amd_dbgapi_write_memory (process_id, wave_id, 0,
status = amd_dbgapi_write_memory (process_id, wave_id, current_lane,
address_space_id, segment_address, &len,
writebuf);

Expand Down
44 changes: 44 additions & 0 deletions gdb/amd-dbgapi-target.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,48 @@ get_status_string (amd_dbgapi_status_t status)
return ret;
}

/* Convenience wrapper around amd_dbgapi_wave_get_info that avoids
manually specifying RES's size and accepts a thread pointer instead
of a wave id. */

template<typename Res>
static amd_dbgapi_status_t
wave_get_info (thread_info *tp, amd_dbgapi_wave_info_t query, Res &res)
{
amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (tp->ptid);

return amd_dbgapi_wave_get_info (wave_id, query, sizeof (res), &res);
}

/* Like wave_get_info above, but throws an error if the dbgapi call
fails. */

template<typename Res>
static void
wave_get_info_throw (thread_info *tp, amd_dbgapi_wave_info_t query, Res &res)
{
amd_dbgapi_wave_id_t wave_id = get_amd_dbgapi_wave_id (tp->ptid);
amd_dbgapi_status_t status
= amd_dbgapi_wave_get_info (wave_id, query, sizeof (res), &res);
if (status != AMD_DBGAPI_STATUS_SUCCESS)
error (_("amd_dbgapi_wave_get_info for wave_%ld failed: %s"),
wave_id.handle, get_status_string (status));
}

/* Convenience wrapper around amd_dbgapi_dispatch_get_info that avoids
manually specifying RES's size and throws an error if the dbgapi
call fails. */

template<typename Res>
static void
dispatch_get_info_throw (amd_dbgapi_dispatch_id_t dispatch_id,
amd_dbgapi_dispatch_info_t query, Res &res)
{
amd_dbgapi_status_t status
= amd_dbgapi_dispatch_get_info (dispatch_id, query, sizeof (res), &res);
if (status != AMD_DBGAPI_STATUS_SUCCESS)
error (_("amd_dbgapi_dispatch_get_info for dispatch_%ld failed: %s"),
dispatch_id.handle, get_status_string (status));
}

#endif /* GDB_AMD_DBGAPI_TARGET_H */
Loading