Skip to content

[TIOVX-1501] Implementing node/graph level debug options #13

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 1 commit into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -283,22 +283,22 @@ static vx_status tivxTestTargetDebugZone(uint8_t id)
vx_status status = (vx_status)VX_SUCCESS;
vx_enum zone = VX_ZONE_INFO;

if(vx_true_e != tivx_get_debug_zone(zone))
if(vx_true_e != tivx_is_zone_enabled(zone))
{
VX_PRINT(VX_ZONE_ERROR,"Invalid result:VX_ZONE_INFO is cleared\n");
status = (vx_status)VX_FAILURE;
}
if(vx_false_e != tivx_get_debug_zone(VX_ZONE_TARGET))
if(vx_false_e != tivx_is_zone_enabled(VX_ZONE_TARGET))
{
VX_PRINT(VX_ZONE_ERROR,"Invalid result:VX_ZONE_TARGET is enabled\n");
status = (vx_status)VX_FAILURE;
}
if(vx_false_e != tivx_get_debug_zone(-1))
if(vx_false_e != tivx_is_zone_enabled(-1))
{
VX_PRINT(VX_ZONE_ERROR,"Invalid result returned for the ARG:-1\n");
status = (vx_status)VX_FAILURE;
}
if(vx_false_e != tivx_get_debug_zone(VX_ZONE_MAX))
if(vx_false_e != tivx_is_zone_enabled(VX_ZONE_MAX))
{
VX_PRINT(VX_ZONE_ERROR,"Invalid result returned for the ARG:'VX_ZONE_MAX'\n");
status = (vx_status)VX_FAILURE;
Expand Down
106 changes: 100 additions & 6 deletions conformance_tests/test_tiovx/test_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*/

#include <VX/vx.h>
#include <TI/tivx_debug.h>
#include <TI/tivx.h>

#include "test_engine/test.h"

Expand Down Expand Up @@ -51,16 +51,110 @@ TEST(tivxDebug, negativeTestGetDebugZone)

vx_enum zone = -1;

ASSERT(vx_false_e == tivx_get_debug_zone(zone));
ASSERT(vx_false_e == tivx_get_debug_zone(VX_ZONE_MAX));
ASSERT(vx_false_e == tivx_get_debug_zone(0));
ASSERT(vx_true_e == tivx_get_debug_zone(1));
ASSERT(vx_false_e == tivx_is_zone_enabled(zone));
ASSERT(vx_false_e == tivx_is_zone_enabled(VX_ZONE_MAX));
ASSERT(vx_false_e == tivx_is_zone_enabled(0));
ASSERT(vx_true_e == tivx_is_zone_enabled(1));
}

TEST(tivxDebug, testSetNodeDebugZone)
{
vx_context context = context_->vx_context_;
vx_graph graph = 0;
vx_kernel kernel = 0;
vx_node node = 0;
vx_uint32 set_zone = (vx_enum)VX_ZONE_INFO;

ASSERT_VX_OBJECT(graph = vxCreateGraph(context), VX_TYPE_GRAPH);
ASSERT_VX_OBJECT(kernel = vxGetKernelByEnum(context, VX_KERNEL_BOX_3x3), VX_TYPE_KERNEL);
ASSERT_VX_OBJECT(node = vxCreateGenericNode(graph, kernel), VX_TYPE_NODE);

set_zone = (vx_enum)VX_ZONE_INFO;
ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxNodeSetDebugZone(node, set_zone, vx_true_e));

set_zone = (vx_enum)VX_ZONE_ERROR;
ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxNodeSetDebugZone(node, set_zone, vx_false_e));

VX_CALL(vxReleaseNode(&node));
VX_CALL(vxReleaseKernel(&kernel));
VX_CALL(vxReleaseGraph(&graph));
}

TEST(tivxDebug, testSetGraphDebugZone)
{
vx_context context = context_->vx_context_;
vx_graph graph = 0;
vx_kernel kernel = 0;
vx_uint32 set_gZone = (vx_enum)VX_ZONE_INFO, set_nZone = (vx_enum)VX_ZONE_WARNING, num_nodes = 10, i;
vx_node node[num_nodes];

ASSERT_VX_OBJECT(kernel = vxGetKernelByEnum(context, VX_KERNEL_BOX_3x3), VX_TYPE_KERNEL);
ASSERT_VX_OBJECT(graph = vxCreateGraph(context), VX_TYPE_GRAPH);

for (i = 0; i < num_nodes; i++)
{
ASSERT_VX_OBJECT(node[i] = vxCreateGenericNode(graph, kernel), VX_TYPE_NODE);

ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxNodeSetDebugZone(node[i], set_nZone, vx_true_e));
}

ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxGraphSetDebugZone(graph, set_gZone, vx_true_e));

set_gZone = (vx_enum)VX_ZONE_WARNING;
ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxGraphSetDebugZone(graph, set_gZone, vx_false_e));

for (i = 0; i < num_nodes; i++)
{
VX_CALL(vxReleaseNode(&node[i]));
}
VX_CALL(vxReleaseKernel(&kernel));
VX_CALL(vxReleaseGraph(&graph));
}

TEST(tivxDebug, negativetestSetNodeDebugZone)
{
vx_context context = context_->vx_context_;
vx_graph graph = 0;
vx_kernel kernel = 0;
vx_node node = 0;
vx_uint32 level;
vx_size size = 0;

ASSERT_VX_OBJECT(graph = vxCreateGraph(context), VX_TYPE_GRAPH);
ASSERT_VX_OBJECT(kernel = vxGetKernelByEnum(context, VX_KERNEL_BOX_3x3), VX_TYPE_KERNEL);
ASSERT_VX_OBJECT(node = vxCreateGenericNode(graph, kernel), VX_TYPE_NODE);

level = VX_ZONE_MAX+1;
ASSERT_EQ_VX_STATUS(VX_ERROR_INVALID_PARAMETERS, tivxNodeSetDebugZone(node, level, vx_true_e));

VX_CALL(vxReleaseNode(&node));
VX_CALL(vxReleaseKernel(&kernel));
VX_CALL(vxReleaseGraph(&graph));
}

TEST(tivxDebug, negativeTestSetGraphDebugZone)
{
vx_context context = context_->vx_context_;
vx_graph graph = 0;
vx_uint32 level;
vx_size size = 0;

ASSERT_VX_OBJECT(graph = vxCreateGraph(context), VX_TYPE_GRAPH);

level = VX_ZONE_MAX+1;
ASSERT_EQ_VX_STATUS(VX_ERROR_INVALID_PARAMETERS, tivxGraphSetDebugZone(graph, level, vx_true_e));

VX_CALL(vxReleaseGraph(&graph));
}

TESTCASE_TESTS(
tivxDebug,
negativeTestSetDebugZone,
negativeTestClrDebugZone,
negativeTestGetDebugZone
negativeTestGetDebugZone,
testSetNodeDebugZone,
testSetGraphDebugZone,
negativetestSetNodeDebugZone,
negativeTestSetGraphDebugZone
)

73 changes: 40 additions & 33 deletions conformance_tests/test_tiovx/test_graph_pipeline.c
Original file line number Diff line number Diff line change
Expand Up @@ -1616,14 +1616,16 @@ TEST_WITH_ARG(tivxGraphPipeline, testTwoNodes, Arg, PARAMETERS)
* - Same input going to multiple nodes
* - Outputs from multiple nodes going to a single node
* - Node taking input from another node as well as from user
* - Graph / node level debugging options at each level of the pipeline
*
*/
TEST_WITH_ARG(tivxGraphPipeline, testFourNodes, Arg, PARAMETERS)
{
vx_context context = context_->vx_context_;
vx_graph graph;
vx_image d0[MAX_NUM_BUF] = {NULL}, d1, d2, d3, d4[MAX_NUM_BUF] = {NULL}, d5[MAX_NUM_BUF] = {NULL};
vx_node n0, n1, n2, n3;
vx_uint32 gLevel = (vx_enum)VX_ZONE_INFO, nLevel = (vx_enum)VX_ZONE_WARNING, new_level = 0, num_nodes=4, num_images=3, i;
vx_image d0[MAX_NUM_BUF] = {NULL}, virtImg[num_images], d4[MAX_NUM_BUF] = {NULL}, d5[MAX_NUM_BUF] = {NULL};
vx_node node[num_nodes];
vx_graph_parameter_queue_params_t graph_parameters_queue_params_list[3];

CT_Image ref_src[MAX_NUM_BUF] = {NULL}, vxdst;
Expand Down Expand Up @@ -1660,33 +1662,37 @@ TEST_WITH_ARG(tivxGraphPipeline, testFourNodes, Arg, PARAMETERS)
ASSERT_VX_OBJECT(d4[buf_id] = vxCreateImage(context, width, height, VX_DF_IMAGE_U8), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(d5[buf_id] = vxCreateImage(context, width, height, VX_DF_IMAGE_U8), VX_TYPE_IMAGE);
}
ASSERT_VX_OBJECT(d1 = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(d2 = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8), VX_TYPE_IMAGE);
ASSERT_VX_OBJECT(d3 = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8), VX_TYPE_IMAGE);

ASSERT_VX_OBJECT(n0 = vxNotNode(graph, d0[0], d1), VX_TYPE_NODE);
ASSERT_VX_OBJECT(n1 = vxNotNode(graph, d1, d2), VX_TYPE_NODE);
ASSERT_VX_OBJECT(n2 = vxOrNode(graph, d1, d2, d3), VX_TYPE_NODE);
ASSERT_VX_OBJECT(n3 = vxAndNode(graph, d3, d4[0], d5[0]), VX_TYPE_NODE);
for (i = 0; i < num_images; i++)
{
ASSERT_VX_OBJECT(virtImg[i] = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8), VX_TYPE_IMAGE);
}

ASSERT_VX_OBJECT(node[0] = vxNotNode(graph, d0[0], virtImg[0]), VX_TYPE_NODE);
ASSERT_VX_OBJECT(node[1] = vxNotNode(graph, virtImg[0], virtImg[1]), VX_TYPE_NODE);
ASSERT_VX_OBJECT(node[2] = vxOrNode(graph, virtImg[0], virtImg[1], virtImg[2]), VX_TYPE_NODE);
ASSERT_VX_OBJECT(node[3] = vxAndNode(graph, virtImg[2], d4[0], d5[0]), VX_TYPE_NODE);

ASSERT_EQ_VX_STATUS(VX_SUCCESS, tivxGraphSetDebugZone(graph, gLevel, vx_true_e));

#if defined(SOC_AM62A)
VX_CALL(vxSetNodeTarget(n0, VX_TARGET_STRING, TIVX_TARGET_DSP1));
VX_CALL(vxSetNodeTarget(n1, VX_TARGET_STRING, TIVX_TARGET_DSP1));
VX_CALL(vxSetNodeTarget(n2, VX_TARGET_STRING, TIVX_TARGET_DSP1));
VX_CALL(vxSetNodeTarget(n3, VX_TARGET_STRING, TIVX_TARGET_DSP1));
VX_CALL(vxSetNodeTarget(node[0], VX_TARGET_STRING, TIVX_TARGET_DSP1));
VX_CALL(vxSetNodeTarget(node[1], VX_TARGET_STRING, TIVX_TARGET_DSP1));
VX_CALL(vxSetNodeTarget(node[2], VX_TARGET_STRING, TIVX_TARGET_DSP1));
VX_CALL(vxSetNodeTarget(node[3], VX_TARGET_STRING, TIVX_TARGET_DSP1));
#else
VX_CALL(vxSetNodeTarget(n0, VX_TARGET_STRING, TIVX_TARGET_DSP1));
VX_CALL(vxSetNodeTarget(n1, VX_TARGET_STRING, TIVX_TARGET_DSP1));
VX_CALL(vxSetNodeTarget(n2, VX_TARGET_STRING, TIVX_TARGET_DSP2));
VX_CALL(vxSetNodeTarget(n3, VX_TARGET_STRING, TIVX_TARGET_DSP2));
VX_CALL(vxSetNodeTarget(node[0], VX_TARGET_STRING, TIVX_TARGET_DSP1));
VX_CALL(vxSetNodeTarget(node[1], VX_TARGET_STRING, TIVX_TARGET_DSP1));
VX_CALL(vxSetNodeTarget(node[2], VX_TARGET_STRING, TIVX_TARGET_DSP2));
VX_CALL(vxSetNodeTarget(node[3], VX_TARGET_STRING, TIVX_TARGET_DSP2));
#endif

/* input @ n0 index 0, becomes graph parameter 0 */
add_graph_parameter_by_node_index(graph, n0, 0);
add_graph_parameter_by_node_index(graph, node[0], 0);
/* input @ n3 index 1, becomes graph parameter 1 */
add_graph_parameter_by_node_index(graph, n3, 1);
add_graph_parameter_by_node_index(graph, node[3], 1);
/* output @ n3 index 2, becomes graph parameter 2 */
add_graph_parameter_by_node_index(graph, n3, 2);
add_graph_parameter_by_node_index(graph, node[3], 2);

/* set graph schedule config such that graph parameter @ index 0, 1, 2 are enqueuable */
graph_parameters_queue_params_list[0].graph_parameter_index = 0;
Expand Down Expand Up @@ -1725,24 +1731,24 @@ TEST_WITH_ARG(tivxGraphPipeline, testFourNodes, Arg, PARAMETERS)
}

/* Validating tivxGetNodeParameterNumBufByIndex API */
VX_CALL(tivxGetNodeParameterNumBufByIndex(n0, 1, &get_num_buf));
VX_CALL(tivxGetNodeParameterNumBufByIndex(node[0], 1, &get_num_buf));

ASSERT(get_num_buf==0);

VX_CALL(set_num_buf_by_node_index(n0, 1, tmp_num_buf));
VX_CALL(set_num_buf_by_node_index(node[0], 1, tmp_num_buf));

/* Validating tivxGetNodeParameterNumBufByIndex API */
VX_CALL(tivxGetNodeParameterNumBufByIndex(n0, 1, &get_num_buf));
VX_CALL(tivxGetNodeParameterNumBufByIndex(node[0], 1, &get_num_buf));

ASSERT(get_num_buf==tmp_num_buf);

/* n1 and n2 run on different targets hence set output of n1 to have multiple buffers so
* that n1 and n2 can run in a pipeline
*/
VX_CALL(set_num_buf_by_node_index(n1, 1, num_buf));
VX_CALL(set_num_buf_by_node_index(node[1], 1, num_buf));

tmp_num_buf = 1;
VX_CALL(set_num_buf_by_node_index(n2, 2, tmp_num_buf));
VX_CALL(set_num_buf_by_node_index(node[2], 2, tmp_num_buf));

VX_CALL(vxVerifyGraph(graph));

Expand Down Expand Up @@ -1826,25 +1832,26 @@ TEST_WITH_ARG(tivxGraphPipeline, testFourNodes, Arg, PARAMETERS)

if(arg_->measure_perf==1)
{
vx_node nodes[] = { n0, n1, n2, n3 };
vx_node nodes[] = { node[0], node[1], node[2], node[3] };

printGraphPipelinePerformance(graph, nodes, 4, exe_time, loop_cnt+num_buf, arg_->width*arg_->height);
}
#endif

VX_CALL(vxReleaseNode(&n0));
VX_CALL(vxReleaseNode(&n1));
VX_CALL(vxReleaseNode(&n2));
VX_CALL(vxReleaseNode(&n3));
for (i = 0; i < num_nodes; i++)
{
VX_CALL(vxReleaseNode(&node[i]));
}
for(buf_id=0; buf_id<num_buf; buf_id++)
{
VX_CALL(vxReleaseImage(&d0[buf_id]));
VX_CALL(vxReleaseImage(&d4[buf_id]));
VX_CALL(vxReleaseImage(&d5[buf_id]));
}
VX_CALL(vxReleaseImage(&d1));
VX_CALL(vxReleaseImage(&d2));
VX_CALL(vxReleaseImage(&d3));
for (i = 0; i < num_images; i++)
{
VX_CALL(vxReleaseImage(&virtImg[i]));
}
VX_CALL(log_graph_rt_trace_disable(graph, filename));
VX_CALL(vxReleaseGraph(&graph));

Expand Down
59 changes: 51 additions & 8 deletions include/TI/tivx_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
#define TIVX_DEBUG_H

#include <stdbool.h>
#include <VX/vx.h>

/*! \brief Macros for build time check
* \ingroup group_tivx_platform
*/
Expand All @@ -74,6 +76,8 @@
#define BUILD_ASSERT(e) \
enum { ASSERT_CONCAT(assert_line_, __LINE__) = (1U/(e)) }

#define ZONE_BIT(zone) ((vx_uint32)1U << (zone))

/*!
* \file
* \brief The Internal Debugging API
Expand Down Expand Up @@ -110,28 +114,39 @@ enum tivx_debug_zone_e {

VX_ZONE_OPTIMIZATION = 19, /*!< Used to provide optimization tips */

VX_ZONE_MAX = 32
VX_ZONE_MAX = 32 /*!< Maximum value a debug zone can be mapped to */
};

#define VX_PRINT(zone, message, ...) do { tivx_print(((vx_enum)zone), "[%s:%u] " message, __FUNCTION__, __LINE__, ## __VA_ARGS__); } while (1 == 0)

/*! \def VX_PRINT
* \brief The OpenVX Debugging Facility.
* \brief Utility macro to print debug information if specified zone is globally set
* \ingroup group_vx_debug
*/
#define VX_PRINT(zone, message, ...) do { tivx_print_global(((vx_enum)zone), "[%s:%u] " message, __FUNCTION__, __LINE__, ## __VA_ARGS__); } while (1 == 0)

#define VX_PRINT_LOCAL(zone, debug_zonemask, message, ...) do { tivx_print_object(((vx_enum)zone), debug_zonemask, "[%s:%u] " message, __FUNCTION__, __LINE__, ## __VA_ARGS__); } while (1 == 0)

Choose a reason for hiding this comment

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

Proposal: change to
#define VX_PRINT_LOCAL(zone, object, message, ...) do { tivx_print_object(((vx_enum)zone), object->debug_zonemask, etc.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed with proposal, adding to implementation


#ifdef __cplusplus
extern "C" {
#endif

/*! \brief Internal Printing Function.
* \param [in] zone The debug zone from \ref tivx_debug_zone_e.
vx_char *tivx_find_zone_name(vx_enum zone);

/*! \brief Internal printing function for the global debug zone bitmask
* \param [in] zone The debug zone from \ref tivx_debug_zone_e required to print the given message.
* \param [in] format The format string to print.
* \param [in] ... The variable list of arguments.
* \ingroup group_vx_debug
*/
void tivx_print_global(vx_enum zone, const char *format, ...);

/*! \brief Internal printing function for a framework object with a set debug zone bitmask
* \param [in] zone The debug zone from \ref tivx_debug_zone_e required to print the given message.
* \param [in] set_zone The debug zone bitmask of a framework object
* \param [in] format The format string to print.
* \param [in] ... The variable list of arguments.
* \ingroup group_vx_debug
*/
void tivx_print(vx_enum zone, const char *format, ...);
void tivx_print_object(vx_enum zone, vx_uint32 debug_zonemask, const char *format, ...);

/*! \brief Sets a zone bit in the debug mask
* \param [in] zone The debug zone from \ref tivx_debug_zone_e.
Expand All @@ -149,7 +164,35 @@ void tivx_clr_debug_zone(vx_enum zone);
* \param [in] zone The debug zone from \ref tivx_debug_zone_e.
* \ingroup group_vx_debug
*/
vx_bool tivx_get_debug_zone(vx_enum zone);
vx_bool tivx_is_zone_enabled(vx_enum zone);

/*! \brief Returns the global debug zone bitmask
* \param [out] vx_uint32 The global debug zone bitmask
* \ingroup group_vx_debug
*/
vx_uint32 tivx_get_global_zonemask(void);

/*!
* \brief Sets or clears a given debug zone for a graph
*
* \param [in] graph Graph reference
* \param [in] debug_zone Given debug zone enumeration
* \param [in] enable Flag to indicate if zone should be enabled or disabled
*
* \ingroup group_vx_graph
*/
vx_status tivxGraphSetDebugZone(vx_graph graph, vx_uint32 debug_zone, vx_bool enable);

Choose a reason for hiding this comment

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

Here I would like to consider the integration with our runtime debug configuration infrastructure. We use DLT Viewer (Diagnosis and Logging Tool Viewer, https://github.com/COVESA/dlt-viewer)

The tivxGraphSetDebugZone() and tivxNodeSetDebugZone() look acceptable to use with the DLT Viewer.

For the runtime configuration we need the list of the created OVX objects like graphs and nodes.
We can select the object of interest by its name and specify required debug mask using DLT callback feature.

DLT Viewer is usually started after the OVX executable is running. Problem: how can we control debug zone at runtime to debug Graph verify?

Another integration level would be to have DLT Context feature
One Nice to Have could be to make it possible to modify DLT viewer contect tree on Graph/Node creation registering application callback on the OVX object creation. Is it possible with the current TI OVX?

Copy link
Contributor

Choose a reason for hiding this comment

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

The new APIs can be called at any time, including after the graph verify phase. Therefore, changes can be made to the levels of specific nodes and graphs even at runtime. As far as DLT viewer integration goes with graph/node callbacks, we have filed tasks to explore DLT in greater depth in the next release. After doing so, we will be able to better address this point and work with you to understand this issue.


/*!
* \brief Sets or clears a given debug zone for a node
*
* \param [in] node Node reference
* \param [in] debug_zone Given debug zone enumeration
* \param [in] enable Flag to indicate if zone should be enabled or disabled
*
* \ingroup group_vx_node
*/
vx_status tivxNodeSetDebugZone(vx_node node, vx_uint32 debug_zone, vx_bool enable);

#ifdef __cplusplus
}
Expand Down
Loading