This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

J784S4XEVM: Graph execution get stuck

Part Number: J784S4XEVM

Tool/software:

Hello everybody,

i am facing a stucked graph execution and i need some support to solve that problem.

First of all to the circumstances:

PSDK RTOS Version: 09_01_00_06

PSDK Linux Version: 09_01_00_06

I was able to exctract the problem from a complex project, so i have written a small quick and dirty program which executes a small graph.

Following graph gets stuck while executing:

The graph is pretty simple. I have a CSI Node, an user node histogram equalization and a display node. Currently no image sensor is connected, so i register an error frame which is send after the CSI timeout is expired. Normaly the graph should run after the error frame is send to the CSI node. Unfortunatly the graph runs only the first time after the initial timeout is expired and get stuck while running the second iteration. The histogram equalization node is not executed and the main programm is waiting for the graph to finish execution (endless waiting). The code is shown bellow.

I tried to modify the graph so i can enclose the problem to a specific node. I created following two graphs by commenting out the histogram equalization node or the display node, resulting in this two graphs: 

Without a display node, the resulting histogram image is saved in a bmp file. The resulting output images from the histogram node are correct.

Without the histogram node, the error frame is directly transfered to the display node, which shows the error frame correctly.

Both graphs are executed normaly and the program finished successfull. All iterations are executed.

I was not able to discover the problem which leads to the stucked graph and i can not explain myself why the other two graphes are executed normaly. There is no error in my user defined histogram kernel, otherwise the graph without the display node would not run successfully.

Please let me know if you need more informations (more code, callstack, etc.)

Source Code:

#include "own_tracking.h"

#include <TI/hwa_kernels.h>
#include <TI/soc/tivx_soc_j784s4.h>
#include <TI/tivx.h>
#include <TI/video_io_capture.h>
#include <TI/video_io_display.h>
#include <TI/video_io_kernels.h>
#include <VX/vx.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <tivx_utils.h>
#include <tivx_utils_file_rd_wr.h>
#include <unistd.h>
#include <utils/mem/include/app_mem.h>

#define IMG_HEIGHT           480
#define IMG_WIDTH            640
#define DISPLAY_WIDTH        1920
#define DISPLAY_HEIGHT       1080
#define CSI_LANES            4
#define CSI_TIMEOUT_MS       500
#define CSI_TIMEOUT_INIT_MS  10000
#define CLIP_LIMIT_PROZENT   40
#define NUM_GRAPH_EXECUTIONS 100

extern int32_t appCommonInit();
extern int32_t appCommonDeInit();

void error_check(vx_reference reference);
void init_csi_params(tivx_capture_params_t *params);
void init_display_params(tivx_display_params_t *params);
void set_reference_names();
void run_graph();
void release();
void deinit();
void init();

vx_image create_error_frame();

vx_context context;
vx_graph graph;
vx_node node_csi, node_hist, node_display;

vx_user_data_object usr_data_csi, usr_data_display;
vx_object_array array_csi_image;
vx_image img_exemplar, img_csi, img_hist, img_error_frame;
vx_scalar scalar_clip;

int main(int argc, char **argv)
{
    vx_status status;

    tivx_display_params_t params_display;
    tivx_capture_params_t params_csi;
    vx_uint8 clip_limit;

    clip_limit = CLIP_LIMIT_PROZENT;

    init();

    context = vxCreateContext();

    error_check((vx_reference) context);

    graph = vxCreateGraph(context);

    error_check((vx_reference) graph);

    ownTrackingLoadKernels(context, true);
    ownRegisterTrackingA72Kernels();

#ifndef x86_64
    tivxVideoIOLoadKernels(context);
#endif

    init_csi_params(&params_csi);

    usr_data_csi = vxCreateUserDataObject(context,
                                          "tivx_capture_params_t",
                                          sizeof(tivx_capture_params_t),
                                          &params_csi);

    error_check((vx_reference) usr_data_csi);

    img_exemplar =
        vxCreateImage(context, IMG_WIDTH, IMG_HEIGHT, VX_DF_IMAGE_U16);

    error_check((vx_reference) img_exemplar);

    array_csi_image =
        vxCreateObjectArray(context, (vx_reference) img_exemplar, 1);

    error_check((vx_reference) array_csi_image);

    node_csi = tivxCaptureNode(graph, usr_data_csi, array_csi_image);

    error_check((vx_reference) node_csi);

    vxSetNodeTarget(node_csi, VX_TARGET_STRING, TIVX_TARGET_CAPTURE1);

    img_csi = (vx_image) vxGetObjectArrayItem(array_csi_image, 0);

    error_check((vx_reference) img_csi);

    img_hist = vxCreateImage(context, IMG_WIDTH, IMG_HEIGHT, VX_DF_IMAGE_U8);

    error_check((vx_reference) img_hist);

    scalar_clip = vxCreateScalar(context, VX_TYPE_UINT8, &clip_limit);

    error_check((vx_reference) scalar_clip);

    // comment out next two lines for graph without histogram node
    node_hist = ownHistogramEqualNode(graph, img_csi, img_hist, scalar_clip);
    error_check((vx_reference) node_hist);

    init_display_params(&params_display);

    usr_data_display = vxCreateUserDataObject(context,
                                              "tivx_display_params_t",
                                              sizeof(params_display),
                                              (void *) &params_display);

    error_check((vx_reference) usr_data_display);

    // comment out next line for graph without display node
    node_display = tivxDisplayNode(graph, usr_data_display, img_hist);

    // uncomment the next line for graph without histogram node
    // node_display = tivxDisplayNode(graph, usr_data_display, img_csi);
    error_check((vx_reference) node_display);

    status = vxVerifyGraph(graph);

    if (status != VX_SUCCESS) error_check(NULL);

    img_error_frame = create_error_frame();

    error_check((vx_reference) img_error_frame);

    tivxCaptureRegisterErrorFrame(node_csi, (vx_reference) img_error_frame);

    set_reference_names();

    tivxExportGraphToDot(graph,
                         "/home/root/xcorr_app/graph_out",
                         "test_graphs");

    run_graph();
    printf("Successfully executed csi graph ! \n");

    release();
    deinit();

    return EXIT_SUCCESS;
}

void error_check(vx_reference reference)
{
    vx_status status;

    status = vxGetStatus(reference);

    if (status != VX_SUCCESS)
    {
        release();
        deinit();
        exit(EXIT_FAILURE);
    }
}

void init_csi_params(tivx_capture_params_t *params)
{
    tivx_capture_params_init(params);

    params->timeout        = CSI_TIMEOUT_MS;
    params->timeoutInitial = CSI_TIMEOUT_INIT_MS;

    params->numInst = 1U;
    params->numCh   = 1U;
    {
        vx_uint8 ch, id, lane, q;
        for (id = 0; id < params->numInst; id++)
        {
            params->instId[id]                       = id;
            params->instCfg[id].enableCsiv2p0Support = (uint32_t) vx_true_e;
            params->instCfg[id].numDataLanes         = CSI_LANES;
            params->instCfg[id].laneBandSpeed =
                TIVX_CAPTURE_LANE_BAND_SPEED_2000_TO_2250_MBPS;

            for (lane = 0; lane < params->instCfg[id].numDataLanes; lane++)
            {
                params->instCfg[id].dataLanesMap[lane] = lane + 1;
            }
            for (q = 0; q < 4; q++)
            {
                ch                    = (4 - 1) * id + q;
                params->chVcNum[ch]   = q;
                params->chInstMap[ch] = id;
            }
        }
    }
}

void init_display_params(tivx_display_params_t *params)
{
    memset(params, 0, sizeof(tivx_display_params_t));

    if (tivxIsTargetEnabled(TIVX_TARGET_DISPLAY1) == vx_true_e)
    {

        params->opMode    = TIVX_KERNEL_DISPLAY_ZERO_BUFFER_COPY_MODE;
        params->pipeId    = 0;
        params->outWidth  = IMG_WIDTH;
        params->outHeight = IMG_HEIGHT;
        params->posX      = (DISPLAY_WIDTH - IMG_WIDTH) / 2;
        params->posY      = (DISPLAY_HEIGHT - IMG_HEIGHT) / 2;
    }
}

void set_reference_names()
{
    vxSetReferenceName((vx_reference) img_csi, "CSI OUTPUT IMAGE");
    vxSetReferenceName((vx_reference) img_error_frame, "ERROR FRAME IMAGE");
    vxSetReferenceName((vx_reference) img_hist, "HISTOGRAM EQUALIZATION IMAGE");
    vxSetReferenceName((vx_reference) array_csi_image, "CSI OUTPUT 'ARRAY");
    vxSetReferenceName((vx_reference) usr_data_display, "DISPLAY USER DATA");
    vxSetReferenceName((vx_reference) usr_data_csi, "CSI USER DATA");
    vxSetReferenceName((vx_reference) scalar_clip, "CLIP LIMIT SCALAR");

    vxSetReferenceName((vx_reference) node_csi, "CSI NODE");
    vxSetReferenceName((vx_reference) node_display, "DISPLAY NODE");
    vxSetReferenceName((vx_reference) node_hist, "HISTOGRAM EQUALIZATION NODE");

    vxSetReferenceName((vx_reference) graph, "CSI TEST GRAPH");
}

void run_graph()
{
    vx_status status;

    for (int i = 0; i < NUM_GRAPH_EXECUTIONS; ++i)
    {
        char outfilename[200];
        printf("Run %d. iteration !\n", i);

        status = vxScheduleGraph(graph);
        if (status != VX_SUCCESS) error_check(NULL);

        status = vxWaitGraph(graph);
        if (status != VX_SUCCESS) error_check(NULL);

        sprintf(outfilename,
                "/home/root/xcorr_app/test_images/images/%s_%04d.bmp",
                "out",
                i);
        tivx_utils_save_vximage_to_bmpfile(outfilename, img_hist);
    }
}

void release()
{
    if (img_csi != NULL) vxReleaseImage(&img_csi);
    if (img_hist != NULL) vxReleaseImage(&img_hist);
    if (img_error_frame != NULL) vxReleaseImage(&img_error_frame);
    if (img_exemplar != NULL) vxReleaseImage(&img_exemplar);

    if (usr_data_csi != NULL) vxReleaseUserDataObject(&usr_data_csi);
    if (usr_data_display != NULL) vxReleaseUserDataObject(&usr_data_display);

    if (array_csi_image != NULL) vxReleaseObjectArray(&array_csi_image);

    if (scalar_clip != NULL) vxReleaseScalar(&scalar_clip);

    if (node_csi != NULL) vxReleaseNode(&node_csi);
    if (node_display != NULL) vxReleaseNode(&node_display);
    if (node_hist != NULL) vxReleaseNode(&node_hist);

    ownTrackingUnLoadKernels(context);

#ifndef x86_64
    tivxVideoIOUnLoadKernels(context);
#endif

    if (graph != NULL) vxReleaseGraph(&graph);
    if (context != NULL) vxReleaseContext(&context);
}

void deinit()
{
    tivxHostDeInit();
    tivxDeInit();
    appCommonDeInit();

    if (appMemDeInit() != 0) { printf("Failed to deinit memory !\n"); }
}

void init()
{
    appMemInit(NULL);
    appCommonInit();
    tivxInit();
    tivxHostInit();
}

vx_image create_error_frame()
{
    vx_status status;
    vx_image error_frame, error_image;
    vx_size size;
    vx_rectangle_t rect             = { 0 };
    vx_imagepatch_addressing_t addr = { 0 };

    void *buffer;
    uint16_t *data;

    size = IMG_WIDTH * IMG_HEIGHT * sizeof(vx_uint16);

    buffer = malloc(size);

    rect.end_x = IMG_WIDTH;
    rect.end_y = IMG_HEIGHT;

    addr.dim_x    = IMG_WIDTH;
    addr.dim_y    = IMG_HEIGHT;
    addr.stride_x = 2;
    addr.stride_y = addr.stride_x * IMG_WIDTH;

    error_frame =
        vxCreateImage(context, IMG_WIDTH, IMG_HEIGHT, VX_DF_IMAGE_U16);

    error_image = tivx_utils_create_vximage_from_bmpfile(
        context,
        "/home/root/xcorr_app/test_images/images/error_image.bmp",
        vx_true_e);

    status = vxGetStatus((vx_reference) error_frame);

    if (status != VX_SUCCESS) exit(EXIT_FAILURE);

    status = vxGetStatus((vx_reference) error_image);

    if (status != VX_SUCCESS) exit(EXIT_FAILURE);

    vxCopyImagePatch(error_image,
                     &rect,
                     0,
                     &addr,
                     buffer,
                     VX_READ_ONLY,
                     VX_MEMORY_TYPE_HOST);

    data = (uint16_t *) buffer;

    for (int i = 0; i < (IMG_WIDTH * IMG_HEIGHT); ++i)
    {
        data[i] = data[i] << 6;
    }

    vxCopyImagePatch(error_frame,
                     &rect,
                     0,
                     &addr,
                     buffer,
                     VX_WRITE_ONLY,
                     VX_MEMORY_TYPE_HOST);

    vxReleaseImage(&error_image);

    free(buffer);

    return error_frame;
}

Thank you for your help !

  • Hi,

    Let me look into this and get back to you early next week

    Regards,

    Nikhil

  • Hi,

    Few queries here based on your description.

    1. Could you let me know where the hang is? Is it during the execution of capture node or hist node or the display node?

    2. By 2 graphs, do you mean 2 nodes in 1 graph or 1 node in 1 graph? If later, can you let me know how did you share the data among the graph?

    Regards,

    Nikhil

  • Hi,

    1. The hang is somewhere between the capture node and the hist node. I have debugged the graph, the graph is executed in the first iteration and while the graph is executed in the second iteration the hist node is not executed and my main program hangs inside the vxWaitGraph() method. Because of that i supposed that the hang is inside the capture node. So i created two different graphs additionally to verfiy my assumption. One graph with CSI node and display node and a different graph with CSI node and hist node only. I executed the two different graphs with only two nodes separatly. Both graphs ran without any problems. The problem is therefore not the CSI node, or the hist node or the display node. 

    2.  No, sorry for my poor explanation. In total i have 3 different graphs. One graph with 3 nodes (csi, hist, display), one graph with two nodes (csi, hist) and one graph with two nodes (csi, display). The graphs with only 2 nodes run without any problems. The graph with all 3 nodes hangs.

    3. I share the data among the graph as node parameters, as you can see in my source code or what do you mean exactly ?

    Regards,

    Jonas

  • Hi Jonas,

    Sorry, didn't see the source code attached above. I reviewed the same now

    Is ownHistogramEqualNode() your custom node? I don't see this node in the SDK.

    Also, in your usecase, capture + hist and capture + disp works whereas capt + hist + disp does not work right?

    May I know on which target does hist node run? I don't see a vxSetNodeTarget for this.

    Regards,

    Nikhil

  • Hi Nikhil,

    The ownHistogramEqualNode is my custom node.

    Yes, you are right. 

    I have implemented the custom hist node for the A72 target. So i called 

    ownTrackingLoadKernels(context, true); //load kernel in the openvx framework on host side

    ownRegisterTrackingA72Kernels(); //register hist kernel on target A72, hist kernel is member of the module trackingKernels

    I do not call the vxSetNodeTarget, because there is only one target available for my hist node, so the A72 should be the default target.

    For better undertanding i have attached the code for following methods:

    ownTrackingLoadKernels(); // host side

    ownAddHistEqualKernel(); // host side

    ownRegisterTrackingA72Kenrels(); // target side

    ownAddHistEqualTargetKernel(); // target side

    ownKernelHistEqualProcess(); // target side

    Regards,

    Jonas

    vx_status ownTrackingLoadKernels(vx_context context, vx_bool isTargetMode)
    {
        vx_status status;
    
        isTarget = isTargetMode;
    
        if ((0 == isTrackingKernelsLoad) && (NULL != context))
        {
            void tivxSetSelfCpuId(vx_enum cpu_id);
    
            status = tivxRegisterModule(OWN_TRACKING_MODULE_NAME,
                                        publishKernels,
                                        unPublishKernels);
    
            if (status != VX_SUCCESS)
            {
                printf("[OWN_TRACKING_KERNELS]: ERROR in tivxRegisterModules !\n");
                return status;
            }
    
            status = vxLoadKernels(context, OWN_TRACKING_MODULE_NAME);
    
            if (status != VX_SUCCESS)
            {
                printf("[OWN_TRACKING_KERNELS]: ERROR Failed to load kernels !\n");
                return status;
            }
    
            isTrackingKernelsLoad = 1U;
        }
    
        return VX_SUCCESS;
    }
    
    vx_status ownAddHistEqualKernel(vx_context context)
    {
        vx_kernel kernel = NULL;
        vx_status status;
        vx_enum param_id;
    
        status = vxAllocateUserKernelId(context, &hist_equal_kernel_id);
    
        if (status != VX_SUCCESS)
        {
            printf("[" MESSAGE_NAME "]: Error \
                    vxAllocateUserKernelId failed with status (%d) ! \n",
                   status);
        }
        else
        {
            if (!isTarget)
            {
                kernel = vxAddUserKernel(context,
                                         OWN_TRACKING_KERNEL_HIST_EQUAL_NAME,
                                         hist_equal_kernel_id,
                                         hist_equal_kernel_run,
                                         HIST_EQUAL_NUM_PARAMS,
                                         hist_equal_kernel_validate,
                                         hist_equal_kernel_init,
                                         hist_equal_kernel_deinit);
            }
            else
            {
                kernel = vxAddUserKernel(context,
                                         OWN_TRACKING_KERNEL_HIST_EQUAL_NAME,
                                         hist_equal_kernel_id,
                                         NULL,
                                         HIST_EQUAL_NUM_PARAMS,
                                         hist_equal_kernel_validate,
                                         NULL,
                                         NULL);
            }
        }
    
        status = vxGetStatus((vx_reference) kernel);
    
        if (status != VX_SUCCESS)
        {
            printf("[" MESSAGE_NAME "]: \
                    ERROR vxAddUserKernel failed with status (%d) ! \n",
                   status);
        }
        else
        {
            param_id = HIST_EQUAL_INPUT_IMG_PARAM_INDEX;
            status   = vxAddParameterToKernel(kernel,
                                            param_id,
                                            VX_INPUT,
                                            VX_TYPE_IMAGE,
                                            VX_PARAMETER_STATE_REQUIRED);
    
            if (status == VX_SUCCESS)
            {
                param_id = HIST_EQUAL_OUTPUT_IMG_PARAM_INDEX;
                status   = vxAddParameterToKernel(kernel,
                                                param_id,
                                                VX_OUTPUT,
                                                VX_TYPE_IMAGE,
                                                VX_PARAMETER_STATE_REQUIRED);
            }
    
    
            if (status == VX_SUCCESS)
            {
                param_id = HIST_EQUAL_CLIP_LIMIT_PARAM_INDEX;
                status   = vxAddParameterToKernel(kernel,
                                                param_id,
                                                VX_INPUT,
                                                VX_TYPE_SCALAR,
                                                VX_PARAMETER_STATE_REQUIRED);
            }
    
            if (status != VX_SUCCESS)
            {
                printf("[" MESSAGE_NAME "]: \
                        ERROR vxAddParameterToKernel failed with status (%d), \
                        parameter id (%d) ! \n",
                       status,
                       param_id);
            }
    
            if (status == VX_SUCCESS && isTarget)
            {
                status = tivxAddKernelTarget(kernel, TIVX_TARGET_MPU_0);
            }
    
            if (status == VX_SUCCESS) { status = vxFinalizeKernel(kernel); }
    
            if (status != VX_SUCCESS)
            {
                printf("[" MESSAGE_NAME "]: ERROR vxFinilzeKernel failed ! \n");
                vxReleaseKernel(&kernel);
            }
            else
            {
                printf("[" MESSAGE_NAME "]: SUCCESSFULLY created kernel !\n");
                vx_hist_equal_kernel = kernel;
            }
        }
    
        return status;
    }
    void ownRegisterTrackingA72Kernels()
    {
        tivxRegisterTargetKernels(target_kernel_list, dimof(target_kernel_list));
    }
    
    void ownAddHistEqualTargetKernel()
    {
        char target_name[MAX_TARGET_NAME];
    
        strncpy(target_name, TIVX_TARGET_MPU_0, MAX_TARGET_NAME);
    
        own_hist_equal_target_kernel_a72 =
            tivxAddTargetKernelByName(OWN_TRACKING_KERNEL_HIST_EQUAL_NAME,
                                      target_name,
                                      ownKernelHistEqualProcess,
                                      ownKernelHistEqualCreate,
                                      ownKernelHistEqualDelete,
                                      ownKernelHistEqualControl,
                                      NULL);
    }
    
    vx_status VX_CALLBACK
    ownKernelHistEqualProcess(tivx_target_kernel_instance kernel,
                             tivx_obj_desc_t *obj_desc[],
                             uint16_t num_params,
                             void *priv_arg)
    {
        vx_status status = VX_SUCCESS;
        tivx_obj_desc_image_t *desc_img_input, *desc_img_out;
        tivx_obj_desc_scalar_t *desc_scal_clip_limit;
    
        vx_uint32 img_height, img_width, numPixels, clip_limit;
    
        void *target_ptr_img_in;
        void *target_ptr_img_out;
    
        desc_img_input = (tivx_obj_desc_image_t *)
            tivxGetObjDescElement(obj_desc[HIST_EQUAL_INPUT_IMG_PARAM_INDEX], 0);
        desc_img_out =
            (tivx_obj_desc_image_t *) obj_desc[HIST_EQUAL_OUTPUT_IMG_PARAM_INDEX];
    
        desc_scal_clip_limit = (tivx_obj_desc_scalar_t *)
            obj_desc[HIST_EQUAL_CLIP_LIMIT_PARAM_INDEX];
    
        target_ptr_img_in  = tivxMemShared2TargetPtr(&desc_img_input->mem_ptr[0]);
        target_ptr_img_out = tivxMemShared2TargetPtr(&desc_img_out->mem_ptr[0]);
    
        status |= tivxMemBufferMap(target_ptr_img_in,
                                   desc_img_input->mem_size[0],
                                   VX_MEMORY_TYPE_HOST,
                                   VX_READ_ONLY);
        status |= tivxMemBufferMap(target_ptr_img_out,
                                   desc_img_out->mem_size[0],
                                   VX_MEMORY_TYPE_HOST,
                                   VX_WRITE_ONLY);
    
        if (status != VX_SUCCESS)
        {
            printf("[" MESSAGE_NAME
                   "]: ERROR Process - Failed to map memory buffer ! \n");
            return VX_FAILURE;
        }
    
        img_height   = desc_img_input->height;
        img_width    = desc_img_input->width;
    
        numPixels = img_height * img_width;
    
        clip_limit = numPixels * (desc_scal_clip_limit->data.u08 / 100.0);
    
        if(isCsiImage)
        {
            memset(hist, 0, 16384 * sizeof(int));
            memset(cdf, 0, 16384 * sizeof(int));
            histogram_equalization_a72(target_ptr_img_in,
                                   target_ptr_img_out,
                                   hist,
                                   cdf,
                                   numPixels,
                                   clip_limit,
                                   16384);
        }else
        {
            memset(hist, 0, 256 * sizeof(int));
            memset(cdf, 0, 256 * sizeof(int));
            histogram_equalization_a72(target_ptr_img_in,
                                   target_ptr_img_out,
                                   hist,
                                   cdf,
                                   numPixels,
                                   clip_limit,
                                   256);
        }
    
        status |= tivxMemBufferUnmap(target_ptr_img_in,
                                     desc_img_out->mem_size[0],
                                     VX_MEMORY_TYPE_HOST,
                                     VX_READ_ONLY);
        status |= tivxMemBufferUnmap(target_ptr_img_out,
                                     desc_img_out->mem_size[0],
                                     VX_MEMORY_TYPE_HOST,
                                     VX_WRITE_ONLY);
    
        if (status != VX_SUCCESS)
        {
            printf("[" MESSAGE_NAME
                   "]: ERROR Process - Failed to unmap memory buffer ! \n");
            return VX_FAILURE;
        }
    
        status |= tivxMemBufferUnmap(target_ptr_img_in,
                                   desc_img_input->mem_size[0],
                                   VX_MEMORY_TYPE_HOST,
                                   VX_READ_ONLY);
        status |= tivxMemBufferUnmap(target_ptr_img_out,
                                   desc_img_out->mem_size[0],
                                   VX_MEMORY_TYPE_HOST,
                                   VX_WRITE_ONLY);
    
        return VX_SUCCESS;
    }

  • Hi,

    While the execution of 3 nodes usecase, can you put the logs in the start and end of process callback of all the 3 nodes and check in which node is the hang seen?

    Have you already tried this?

    Regards,

    Nikhil