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

Helper files for debuggers #1158

Merged
merged 12 commits into from
Nov 9, 2023
Merged
11 changes: 11 additions & 0 deletions src/cmake/Setup3rdParty.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,14 @@ if(CALIPER_DIR)
message(FATAL_ERROR "CALIPER_DIR is set, but Caliper wasn't found.")
endif()
endif()

################################
# Setup Totalview if available
################################
# Search for Totalview.
if(TOTALVIEW_DIR)
include(cmake/thirdparty/SetupTotalview.cmake)
if(NOT TOTALVIEW_FOUND)
message(WARNING "TOTALVIEW_DIR is set, but Totalview wasn't found.")
endif()
endif()
29 changes: 29 additions & 0 deletions src/cmake/thirdparty/SetupTotalview.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright (c) Lawrence Livermore National Security, LLC and other Conduit
# Project developers. See top-level LICENSE AND COPYRIGHT files for dates and
# other details. No copyright assignment is required to contribute to Conduit.
###############################################################################
#
# Setup TOTALVIEW


# first Check for TOTALVIEW_DIR

if(TOTALVIEW_DIR)

find_path(TOTALVIEW_INCLUDE_DIRECTORIES
tv_data_display.h
NO_DEFAULT_PATH
PATHS ${TOTALVIEW_DIR}/include)

find_path(TOTALVIEW_SOURCE_DIRECTORY
tv_data_display.c
NO_DEFAULT_PATH
PATHS ${TOTALVIEW_DIR}/src)

if (TOTALVIEW_INCLUDE_DIRECTORIES)
set(TOTALVIEW_FOUND TRUE)
set(CONDUIT_USE_TOTALVIEW TRUE)
set(CONDUIT_EXCLUDE_TV_DATA_DISPLAY FALSE)
endif()

endif()
216 changes: 216 additions & 0 deletions src/debug/gdb/conduit-gdb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Copyright (c) Lawrence Livermore National Security, LLC and other Conduit
# Project developers. See top-level LICENSE AND COPYRIGHT files for dates and
# other details. No copyright assignment is required to contribute to Conduit.

import gdb
import gdb.printing
import itertools


class ConduitTypes:
"""Represent Conduit TypeIDs."""
def __init__(self):
self.EMPTY_ID = gdb.parse_and_eval("(int)conduit::DataType::EMPTY_ID");
self.OBJECT_ID = gdb.parse_and_eval("(int)conduit::DataType::OBJECT_ID");
self.LIST_ID = gdb.parse_and_eval("(int)conduit::DataType::LIST_ID");
self.INT8_ID = gdb.parse_and_eval("(int)conduit::DataType::INT8_ID");
self.INT16_ID = gdb.parse_and_eval("(int)conduit::DataType::INT16_ID");
self.INT32_ID = gdb.parse_and_eval("(int)conduit::DataType::INT32_ID");
self.INT64_ID = gdb.parse_and_eval("(int)conduit::DataType::INT64_ID");
self.UINT8_ID = gdb.parse_and_eval("(int)conduit::DataType::UINT8_ID");
self.UINT16_ID = gdb.parse_and_eval("(int)conduit::DataType::UINT16_ID");
self.UINT32_ID = gdb.parse_and_eval("(int)conduit::DataType::UINT32_ID");
self.UINT64_ID = gdb.parse_and_eval("(int)conduit::DataType::UINT64_ID");
self.FLOAT32_ID = gdb.parse_and_eval("(int)conduit::DataType::FLOAT32_ID");
self.FLOAT64_ID = gdb.parse_and_eval("(int)conduit::DataType::FLOAT64_ID");
self.CHAR8_STR_ID = gdb.parse_and_eval("(int)conduit::DataType::CHAR8_STR_ID");

def type_string(self, val):
dtype_id = self.node_type(val)
tp = ""
if dtype_id == self.INT8_ID:
tp = "char"
elif dtype_id == self.INT16_ID:
tp = "short"
elif dtype_id == self.INT32_ID:
tp = "int"
elif dtype_id == self.INT64_ID:
tp = "long"
elif dtype_id == self.UINT8_ID:
tp = "unsigned char"
elif dtype_id == self.UINT16_ID:
tp = "unsigned short"
elif dtype_id == self.UINT32_ID:
tp = "unsigned int"
elif dtype_id == self.UINT64_ID:
tp = "unsigned long"
elif dtype_id == self.FLOAT32_ID:
tp = "float"
elif dtype_id == self.FLOAT64_ID:
tp = "double"

return tp

def node_type(self, val):
dtype_id = val['m_schema'].dereference()
int_t = gdb.lookup_type('int')
return dtype_id['m_dtype']['m_id'].cast(int_t)

class EmptyNodePrinter:
"""Print an empty conduit::Node object."""

def __init__(self):
pass

def to_string(self):
return "empty Node"


class StringNodePrinter:
"""Print a string conduit::Node object."""

def __init__(self, val, types):
self.types = types
self.val = val

def to_string(self):
t = gdb.lookup_type('const char *').pointer()
v = self.val['m_data'].cast(t)
return v

def display_hint(self):
return 'string'

class ArrayNodePrinter:
"""Print an array numeric conduit::Node object."""

def __init__(self, val, types):
self.types = types
self.val = val
self.num_elts = self.val['m_schema'].dereference()['m_dtype']['m_num_ele']

def to_string(self):
return "{{ array length {0} }}".format(self.num_elts)

def children (self):
tp = self.types.type_string(self.val)
t = gdb.lookup_type(tp).pointer()
v = self.val['m_data'].cast(t)

for i in range(self.num_elts):
yield "[{0}]".format(i), v[i]

def display_hint(self):
return 'array'


class ScalarNodePrinter:
"""Print a scalar numeric conduit::Node object."""

def __init__(self, val, types):
self.types = types
self.val = val

def to_string(self):
tp = self.types.type_string(self.val)
t = gdb.lookup_type(tp).pointer()
v = self.val['m_data'].cast(t)
return v[0]

class TreeNodePrinter:
"""Let subclasses count children."""

def __init__(self, types):
self.types = types

def count_children(self, val):
dtype_id = self.types.node_type(val)

tp = ''
if dtype_id == self.types.OBJECT_ID:
tp = 'conduit::Schema::Schema_Object_Hierarchy'
elif dtype_id == self.types.LIST_ID:
tp = 'conduit::Schema::Schema_List_Hierarchy'

t = gdb.lookup_type(tp).pointer()
hier_data = val['m_schema'].dereference()['m_hierarchy_data'].cast(t).dereference()['children']
hier_data_first = hier_data['_M_impl']['_M_start']
hier_data_last = hier_data['_M_impl']['_M_finish']
return hier_data_last - hier_data_first


class ListNodePrinter(TreeNodePrinter):
"""Print a list conduit::Node object."""

def __init__(self, val, types):
super().__init__(types)
self.val = val
self.num_children = self.count_children(val)

def to_string(self):
return "{{ list length {0} }}".format(self.num_children)

def display_hint(self):
return 'array'

def children (self):
for i in range(self.num_children):
yield ("[{0}]".format(i),
self.val['m_children']['_M_impl']['_M_start'][i].dereference())
# yield ("idx", "lv")


class ObjectNodePrinter(TreeNodePrinter):
"""Print an object conduit::Node object."""

def __init__(self, val, types):
super().__init__(types)
self.val = val
self.num_children = self.count_children(val)

def to_string(self):
return "{{ object children {0} }}".format(self.num_children)

def display_hint(self):
return 'map'

def children (self):
names = self.object_children_names()

for i in range(2*self.num_children):
yield ("{0}".format(names[i]),
self.val['m_children']['_M_impl']['_M_start'][i].dereference())
# return [("blah", "1"), ("blah", "a"), ("blah", "2"), ("blah", "b"), ("blah","3"), ("blah", "c")]

def object_children_names(self):
dtype_id = self.types.node_type(self.val)

if dtype_id == self.types.OBJECT_ID:
tp = 'conduit::Schema::Schema_Object_Hierarchy'
t = gdb.lookup_type(tp).pointer()
return self.val['m_schema'].dereference()['m_hierarchy_data'].cast(t)['object_order']['_M_impl']['_M_start']
else:
return None

def node_pp_function(val):
if str(val.type) == 'conduit::Node':
types = ConduitTypes()
tid = types.node_type(val)
if tid == types.EMPTY_ID:
return EmptyNodePrinter()
elif tid == types.CHAR8_STR_ID:
return StringNodePrinter(val, types)
elif tid == types.LIST_ID:
return ListNodePrinter(val, types)
elif tid == types.OBJECT_ID:
return ObjectNodePrinter(val, types)
else:
elt_count = val['m_schema'].dereference()['m_dtype']['m_num_ele']
if elt_count < 2:
return ScalarNodePrinter(val, types)
else:
return ArrayNodePrinter(val, types)
return None


gdb.pretty_printers.append(node_pp_function)
78 changes: 78 additions & 0 deletions src/debug/msvs/ConduitNode.natvis
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="conduit::Node">
<!-- Node can be empty, object, list, or leaf. -->
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_EMPTY_ID">empty conduit::Node</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_OBJECT_ID">object {{ size: { m_children.size() } }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_LIST_ID">list {{ size: { m_children.size() } }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_INT8_ID">int8 {{ size: {m_schema->m_dtype.m_num_ele} }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_INT16_ID">int16 {{ size: {m_schema->m_dtype.m_num_ele} }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_INT32_ID">int32 {{ size: {m_schema->m_dtype.m_num_ele} }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_INT64_ID">int64 {{ size: {m_schema->m_dtype.m_num_ele} }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_UINT8_ID">uint8 {{ size: {m_schema->m_dtype.m_num_ele} }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_UINT16_ID">uint16 {{ size: {m_schema->m_dtype.m_num_ele} }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_UINT32_ID">int32 {{ size: {m_schema->m_dtype.m_num_ele} }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_UINT64_ID">int64 {{ size: {m_schema->m_dtype.m_num_ele} }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_FLOAT32_ID">float {{ size: {m_schema->m_dtype.m_num_ele} }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_FLOAT64_ID">double {{ size: {m_schema->m_dtype.m_num_ele} }}</DisplayString>
<DisplayString Condition="m_schema->m_dtype.m_id == CONDUIT_CHAR8_STR_ID">string: { (char *)m_data }</DisplayString>
<DisplayString>leaf value</DisplayString>
<Expand>
<ArrayItems Condition="m_schema->m_dtype.m_id == CONDUIT_LIST_ID">
<Size>m_children.size()</Size>
<ValuePointer>m_children._Mypair._Myval2._Myfirst</ValuePointer>
</ArrayItems>
<CustomListItems Condition="m_schema->m_dtype.m_id == CONDUIT_OBJECT_ID">
<Variable Name="i" InitialValue="0"/>
<Variable Name="hier" InitialValue="(conduit::Schema::Schema_Object_Hierarchy *)(m_schema->m_hierarchy_data)"/>
<Size>m_children.size()</Size>
<Loop Condition="i&lt;m_children.size()">
<!-- This works only if the order of the children hasn't been messed up. -->
<!-- I haven't found a way to get a temporary Node here in the loop. -->
Comment on lines +30 to +31
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works in the simple case, for objects that get created and never have Nodes removed. I don't know if I can get this to work in the general case, where the order might get perturbed.

<Item Name="{hier->object_order[i]}">m_children[i]</Item>
<Exec>i++</Exec>
</Loop>
</CustomListItems>
<ArrayItems Condition="m_schema->m_dtype.m_id == CONDUIT_INT8_ID">
<Size>m_schema->m_dtype.m_num_ele</Size>
<ValuePointer>(signed char *)m_data</ValuePointer>
</ArrayItems>
<ArrayItems Condition="m_schema->m_dtype.m_id == CONDUIT_INT16_ID">
<Size>m_schema->m_dtype.m_num_ele</Size>
<ValuePointer>(signed short *)m_data</ValuePointer>
</ArrayItems>
<ArrayItems Condition="m_schema->m_dtype.m_id == CONDUIT_INT32_ID">
<Size>m_schema->m_dtype.m_num_ele</Size>
<ValuePointer>(signed int *)m_data</ValuePointer>
</ArrayItems>
<ArrayItems Condition="m_schema->m_dtype.m_id == CONDUIT_INT64_ID">
<Size>m_schema->m_dtype.m_num_ele</Size>
<ValuePointer>(signed long *)m_data</ValuePointer>
</ArrayItems>
<ArrayItems Condition="m_schema->m_dtype.m_id == CONDUIT_UINT8_ID">
<Size>m_schema->m_dtype.m_num_ele</Size>
<ValuePointer>(unsigned char *)m_data</ValuePointer>
</ArrayItems>
<ArrayItems Condition="m_schema->m_dtype.m_id == CONDUIT_UINT16_ID">
<Size>m_schema->m_dtype.m_num_ele</Size>
<ValuePointer>(unsigned short *)m_data</ValuePointer>
</ArrayItems>
<ArrayItems Condition="m_schema->m_dtype.m_id == CONDUIT_UINT32_ID">
<Size>m_schema->m_dtype.m_num_ele</Size>
<ValuePointer>(unsigned int *)m_data</ValuePointer>
</ArrayItems>
<ArrayItems Condition="m_schema->m_dtype.m_id == CONDUIT_UINT64_ID">
<Size>m_schema->m_dtype.m_num_ele</Size>
<ValuePointer>(unsigned long *)m_data</ValuePointer>
</ArrayItems>
<ArrayItems Condition="m_schema->m_dtype.m_id == CONDUIT_FLOAT32_ID">
<Size>m_schema->m_dtype.m_num_ele</Size>
<ValuePointer>(float *)m_data</ValuePointer>
</ArrayItems>
<ArrayItems Condition="m_schema->m_dtype.m_id == CONDUIT_FLOAT64_ID">
<Size>m_schema->m_dtype.m_num_ele</Size>
<ValuePointer>(double *)m_data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>
Binary file added src/docs/sphinx/debugger_MSVS_Conduit_list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/docs/sphinx/tutorial_cpp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ with C++ and Python examples.
tutorial_cpp_move_and_swap
tutorial_cpp_utils
tutorial_cpp_errors

tutorial_cpp_debugger

Loading
Loading