Skip to content

Commit

Permalink
Helper files for debuggers (#1158)
Browse files Browse the repository at this point in the history
Debugger files for MS Visual Studio (.natvis file) and Totalview (enabled by providing a path to the Totalview installation when configuring with CMake).  GDB is still in progress.

---------

Co-authored-by: Cyrus Harrison <cyrush@llnl.gov>
  • Loading branch information
agcapps and cyrush committed Nov 9, 2023
1 parent 972d627 commit a1e205c
Show file tree
Hide file tree
Showing 13 changed files with 534 additions and 3 deletions.
11 changes: 11 additions & 0 deletions src/cmake/Setup3rdParty.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,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. -->
<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
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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

0 comments on commit a1e205c

Please sign in to comment.