Skip to content
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

Add GDB pretty-printers for range and grid types #207

Merged
merged 3 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .gdbinit
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
python
import sys
sys.path += ['debug/gdb', 'vendor/small_vector/source/support/python']
import celerity.gdb, gch.gdb.prettyprinters.small_vector
end
3 changes: 3 additions & 0 deletions .github/workflows/celerity_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ jobs:
# We build examples twice, but only run the installed version (which probably has more failure modes)
working-directory: ${{ env.examples-build-dir }}
run: ${{ env.container-workspace }}/ci/run-examples.sh /data/Lenna.png 1 2 4
- name: Run debugging tests
if: matrix.build-type == 'Debug' && matrix.sycl == 'hipsycl' # newer DPC++ generates DWARF5 which is incompatible with Ubuntu 20.04's GDB
run: ${{ env.container-workspace }}/test/debug/pretty-print-test.py ${{ env.build-dir }}/test/debug/pretty_printables
- name: Run system tests
working-directory: ${{ env.build-dir }}
run: ${{ env.container-workspace }}/ci/run-system-tests.sh 2 4
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ install
.vscode/
.idea/
/tags
__pycache__/
7 changes: 7 additions & 0 deletions debug/gdb/celerity/gdb/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import gdb

def register_printers(obj):
from .prettyprinters import pretty_printer
gdb.printing.register_pretty_printer(obj, pretty_printer)

register_printers(None)
159 changes: 159 additions & 0 deletions debug/gdb/celerity/gdb/prettyprinters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import gdb
from typing import Iterable, Tuple


def iter_child_values(value: gdb.Value) -> Iterable[gdb.Value]:
for _, child in gdb.default_visualizer(value).children():
yield child


def deref_unique_ptr(unique_ptr: gdb.Value) -> gdb.Value:
children = list(iter_child_values(unique_ptr))
assert len(children) == 1
return children[0].dereference()


def get_variant_content(variant: gdb.Value) -> gdb.Value:
return gdb.default_visualizer(variant).contained_value


class PhantomTypePrinter:
def __init__(self, prefix: str, val: gdb.Value):
self.prefix = prefix
self.value = val['m_value']

def to_string(self) -> str:
return self.prefix + str(self.value)


class CoordinatePrinter:
def __init__(self, val: gdb.Value):
self.values = val['m_values']['values']

def to_string(self) -> str:
i_min, i_max = self.values.type.range()
return '[' + ', '.join(str(self.values[i]) for i in range(i_min, i_max+1)) + ']'


class SubrangePrinter:
def __init__(self, val: gdb.Value):
self.offset = val['offset']
self.range = val['range']

def to_string(self) -> str:
return str(self.offset) + ' + ' + str(self.range)


class NdRangePrinter:
def __init__(self, val):
self.global_range = val['m_global_range']
self.local_range = val['m_local_range']
self.offset = val['m_offset']

def children(self) -> Iterable[Tuple[str, gdb.Value]]:
yield 'global_range', self.global_range
yield 'local_range', self.local_range
yield 'offset', self.offset


class ChunkPrinter:
def __init__(self, val: gdb.Value):
self.offset = val['offset']
self.range = val['range']
self.global_size = val['global_size']

def children(self) -> Iterable[Tuple[str, gdb.Value]]:
yield 'offset', self.offset
yield 'range', self.range
yield 'global_size', self.global_size


class BoxPrinter:
def __init__(self, val: gdb.Value):
self.min = val['m_min']
self.max = val['m_max']

def to_string(self) -> str:
return str(self.min) + ' - ' + str(self.max)


class RegionPrinter:
def __init__(self, val: gdb.Value):
self.boxes = val['m_boxes']

def to_string(self) -> str:
if next(gdb.default_visualizer(self.boxes).children(), None) is None:
return '{}'

def children(self) -> Iterable[gdb.Value]:
return gdb.default_visualizer(self.boxes).children()

def display_hint(self) -> str:
return 'array'


class RegionMapPrinter:
def __init__(self, val: gdb.Value):
impl = get_variant_content(val['m_region_map'])
self.extent = impl['m_extent']
self.root = deref_unique_ptr(impl['m_root'])

def to_string(self) -> str:
return 'region_map({})'.format(self.extent)

def children(self) -> Iterable[Tuple[str, gdb.Value]]:
def recurse_tree(root: gdb.Value):
child_boxes = root['m_child_boxes']
children = root['m_children']
for box, child in zip(iter_child_values(child_boxes), iter_child_values(children)):
child = get_variant_content(child)
if 'celerity::detail::region_map_detail::inner_node' in str(child.type):
yield from recurse_tree(deref_unique_ptr(child))
else:
yield ('[' + str(box) + ']', child)
yield from recurse_tree(self.root)


class WriteCommandStatePrinter:
def __init__(self, val: gdb.Value):
bits = int(val['m_cid']['m_value'])
self.cid = (bits & 0x3fff_ffff_ffff_ffff)
self.fresh = (bits & 0x8000_0000_0000_0000) == 0
self.replicated = (bits & 0x4000_0000_0000_0000) != 0

def to_string(self) -> str:
return 'C{} ({}{})'.format(self.cid,
'fresh' if self.fresh else 'stale',
', replicated' if self.replicated else '')


def add_phantom_type_printer(pp: gdb.printing.RegexpCollectionPrettyPrinter, type: str, prefix: str):
pp.add_printer(type, '^celerity::detail::PhantomType<.*celerity::detail::{}_PhantomType>$'.format(type),
lambda val: PhantomTypePrinter(prefix, val))


def build_pretty_printer():
pp = gdb.printing.RegexpCollectionPrettyPrinter("Celerity")
add_phantom_type_printer(pp, 'task_id', 'T')
add_phantom_type_printer(pp, 'buffer_id', 'B')
add_phantom_type_printer(pp, 'node_id', 'N')
add_phantom_type_printer(pp, 'command_id', 'C')
add_phantom_type_printer(pp, 'collective_group_id', 'CG')
add_phantom_type_printer(pp, 'reduction_id', 'R')
add_phantom_type_printer(pp, 'host_object_id', 'H')
add_phantom_type_printer(pp, 'hydration_id', 'HY')
add_phantom_type_printer(pp, 'transfer_id', 'TR')
pp.add_printer('id', '^celerity::id<.*>$', CoordinatePrinter)
pp.add_printer('range', '^celerity::range<.*>$', CoordinatePrinter)
pp.add_printer('subrange', '^celerity::subrange<.*>$', SubrangePrinter)
pp.add_printer('nd_range', '^celerity::nd_range<.*>$', NdRangePrinter)
pp.add_printer('chunk', '^celerity::chunk<.*>$', ChunkPrinter)
pp.add_printer('box', '^celerity::detail::box<.*>$', BoxPrinter)
pp.add_printer('region', '^celerity::detail::region<.*>$', RegionPrinter)
pp.add_printer('region_map', '^celerity::detail::region_map<.*>$', RegionMapPrinter)
pp.add_printer('write_command_state', '^celerity::detail::write_command_state$', WriteCommandStatePrinter)

return pp


pretty_printer = build_pretty_printer()
10 changes: 5 additions & 5 deletions include/distributed_graph_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ using node_bitset = std::bitset<max_num_nodes>;
* - Whether this data has been replicated from somewhere else, i.e., we are not the original producer
*/
class write_command_state {
constexpr static int64_t fresh_bit = 1ll << 63;
constexpr static int64_t stale_bit = 1ll << 63;
constexpr static int64_t replicated_bit = 1ll << 62;
static_assert(sizeof(fresh_bit) == sizeof(command_id));
static_assert(sizeof(stale_bit) == sizeof(command_id));

public:
constexpr write_command_state() = default;
Expand All @@ -40,13 +40,13 @@ class write_command_state {
if(is_replicated) { m_cid |= replicated_bit; }
}

bool is_fresh() const { return (m_cid & fresh_bit) == 0u; }
bool is_fresh() const { return (m_cid & stale_bit) == 0u; }

bool is_replicated() const { return (m_cid & replicated_bit) != 0u; }

void mark_as_stale() { m_cid |= fresh_bit; }
void mark_as_stale() { m_cid |= stale_bit; }

operator command_id() const { return m_cid & ~fresh_bit & ~replicated_bit; }
operator command_id() const { return m_cid & ~stale_bit & ~replicated_bit; }

friend bool operator==(const write_command_state& lhs, const write_command_state& rhs) { return lhs.m_cid == rhs.m_cid; }

Expand Down
4 changes: 4 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,7 @@ if(CAIRO_INCLUDE_DIRS AND CAIRO_LIBRARIES)
endforeach()
target_link_libraries(all_tests PRIVATE ${CAIRO_LIBRARIES})
endif()

if(CMAKE_BUILD_TYPE STREQUAL Debug)
add_subdirectory(debug)
endif()
2 changes: 2 additions & 0 deletions test/debug/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
add_executable(pretty_printables pretty_printables.cc)
add_celerity_to_target(TARGET pretty_printables SOURCES pretty_printables.cc)
40 changes: 40 additions & 0 deletions test/debug/pretty-print-test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env python3

import subprocess
import sys

EXPECTED = b'''__builtin_trap();
tid = T10
bid = B11
nid = N12
cid = C13
cgid = CG14
rid = R15
hoid = H16
hyid = HY17
trid = TR18
id = [1, 2, 3]
range = [1, 2, 3]
subrange = [1, 2, 3] + [4, 5, 6]
chunk = {offset = [1, 2, 3], range = [4, 5, 6], global_size = [7, 8, 9]}
nd_range = {global_range = [2, 4, 6], local_range = [1, 2, 3], offset = [7, 8, 9]}
box = [1, 2, 3] - [4, 5, 6]
empty_region = {}
region = {[1, 2, 3] - [4, 5, 6], [11, 2, 3] - [14, 5, 6], [21, 2, 3] - [24, 5, 6]}
region_map = region_map([0, 0, 0] - [10, 10, 10]) = {[[0, 0, 0] - [10, 10, 1]] = 0, [[0, 0, 5] - [10, 10, 10]] = 0, [[0, 0, 1] - [10, 1, 5]] = 0, [[0, 5, 1] - [10, 10, 5]] = 0, [[0, 1, 1] - [1, 5, 5]] = 0, [[1, 1, 1] - [2, 2, 2]] = 1337, [[1, 1, 2] - [3, 3, 3]] = 69, [[1, 2, 1] - [3, 3, 2]] = 69, [[2, 1, 1] - [3, 2, 2]] = 69, [[1, 1, 3] - [5, 5, 5]] = 42, [[3, 1, 1] - [5, 3, 3]] = 42, [[1, 3, 1] - [5, 5, 3]] = 42, [[5, 1, 1] - [10, 5, 5]] = 0}
wcs_fresh = C123 (fresh)
wcs_stale = C123 (stale)
wcs_replicated = C123 (fresh, replicated)
'''

# invoke as `pretty-print-test.py build/test/debug/pretty_printables`
assert len(sys.argv) == 2

out = subprocess.check_output(['gdb', '-batch', sys.argv[1], '-ex', 'r', '-ex', 'i locals'])
if not out.endswith(EXPECTED):
print('-*- pretty-print test FAILED: expected GDB output to end with', file=sys.stderr)
print(EXPECTED.decode('utf-8'), file=sys.stderr)
print('-*- but got', file=sys.stderr)
print(out.decode('utf-8'), file=sys.stderr)
print('-*-', file=sys.stderr)
sys.exit(1)
43 changes: 43 additions & 0 deletions test/debug/pretty_printables.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "distributed_graph_generator.h"
#include "grid.h"
#include "ranges.h"
#include "region_map.h"
#include "types.h"

int main() {
[[maybe_unused]] celerity::detail::task_id tid = 10;
fknorr marked this conversation as resolved.
Show resolved Hide resolved
[[maybe_unused]] celerity::detail::buffer_id bid = 11;
fknorr marked this conversation as resolved.
Show resolved Hide resolved
[[maybe_unused]] celerity::detail::node_id nid = 12;
fknorr marked this conversation as resolved.
Show resolved Hide resolved
[[maybe_unused]] celerity::detail::command_id cid = 13;
fknorr marked this conversation as resolved.
Show resolved Hide resolved
[[maybe_unused]] celerity::detail::collective_group_id cgid = 14;
fknorr marked this conversation as resolved.
Show resolved Hide resolved
[[maybe_unused]] celerity::detail::reduction_id rid = 15;
fknorr marked this conversation as resolved.
Show resolved Hide resolved
[[maybe_unused]] celerity::detail::host_object_id hoid = 16;
fknorr marked this conversation as resolved.
Show resolved Hide resolved
[[maybe_unused]] celerity::detail::hydration_id hyid = 17;
fknorr marked this conversation as resolved.
Show resolved Hide resolved
[[maybe_unused]] celerity::detail::transfer_id trid = 18;
fknorr marked this conversation as resolved.
Show resolved Hide resolved

[[maybe_unused]] celerity::id<3> id(1, 2, 3);
[[maybe_unused]] celerity::range<3> range(1, 2, 3);
[[maybe_unused]] celerity::subrange<3> subrange(celerity::id(1, 2, 3), celerity::range(4, 5, 6));
[[maybe_unused]] celerity::chunk<3> chunk(celerity::id(1, 2, 3), celerity::range(4, 5, 6), celerity::range(7, 8, 9));
[[maybe_unused]] celerity::nd_range<3> nd_range(celerity::range(2, 4, 6), celerity::range(1, 2, 3), celerity::id(7, 8, 9));
[[maybe_unused]] celerity::detail::box<3> box(celerity::id(1, 2, 3), celerity::id(4, 5, 6));
[[maybe_unused]] celerity::detail::region<3> empty_region;
[[maybe_unused]] celerity::detail::region<3> region({
celerity::detail::box(celerity::id(1, 2, 3), celerity::id(4, 5, 6)),
celerity::detail::box(celerity::id(11, 2, 3), celerity::id(14, 5, 6)),
celerity::detail::box(celerity::id(21, 2, 3), celerity::id(24, 5, 6)),
});

[[maybe_unused]] celerity::detail::region_map<int> region_map(celerity::range<3>(10, 10, 10), 3);
region_map.update_region(celerity::detail::box<3>({1, 1, 1}, {5, 5, 5}), 42);
region_map.update_region(celerity::detail::box<3>({1, 1, 1}, {3, 3, 3}), 69);
region_map.update_region(celerity::detail::box<3>({1, 1, 1}, {2, 2, 2}), 1337);

[[maybe_unused]] celerity::detail::write_command_state wcs_fresh(celerity::detail::command_id(123));
[[maybe_unused]] celerity::detail::write_command_state wcs_stale(celerity::detail::command_id(123));
wcs_stale.mark_as_stale();
[[maybe_unused]] celerity::detail::write_command_state wcs_replicated(celerity::detail::command_id(123), true /* replicated */);

// tell GDB to break here so we can examine locals
__builtin_trap();
}
Loading