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.

TMS320C6748: VLIB 3_3_0_3 , VLIB_createCCMap8Bit problem

Part Number: TMS320C6748

Hey,
I have a problem with VLIB_createCCMap8Bit, it create wrong 8 bit map,

for this mask :

with minArea = 10

it gives a correct 8 bit map, but with two 103 values  at index : (175,217), (176,217) (which cause a memory corruption in my case, since we support up to 10 regions)

Is this a known bug ?

  • The team is notified. They will post their feedback directly here.

    BR
    Tsvetolin Shulev
  • Our system blocks google drive links. Can you please attach the necessary files, configuration, and input so that we can investigate or reproduce on our side?
  • I called :

    VLIB_createConnectedComponentsList(   handle, //  VLIB_CCHandle handle[26];
                                            im_size_x,
                                            im_size_y,
                                            (uint32_t *)input_image,
                                            min_blob_area,
                                            connectedCompFlag);
    im_size_x = im_size_y = 224
    min_blob_area = 10
    connectedCompFlag = 1
    then :
    VLIB_getNumCCs(handle, numCCs);
    then :
        for(i = 0; i < *numCCs; i++)
    VLIB_getCCFeatures(handle, (VLIB_CC*)&CCs[i], i); // CCs =   VLIB_CC vlib_cc[256];
    then:
    VLIB_createCCMap8Bit(handle, aligned_image, im_size_x, im_size_y);  // aligned_mage  = 
    #pragma DATA_ALIGN(aligned_image, 0x20)
    unsigned char aligned_image[50176];
  • Mohammad,

    I have taken your input mask and settings and added the test vector to the VLIB_Connected_Components_Labeling unit test that is delivered with VLIB, and I can not reproduce the problem.

    I have attached my modified _idat.c file, and console output when I modify the "LevelOfFeedback" argument in the _d.c file from 0 to 1.  As you can see, the CCMap shows 0s in the 2 locations you mentioned.  Can you confirm that my updated unit test vector (first one in list) accurately matches your input and settings?

    Perhaps you can replace the _idat.c file in the unit test in your side, recompile and run the unit test to see if you get the same results as I do.  If so, perhaps it would be easier to debug using the difference between this test and your application.  I wonder if there is some other source of memory corruption or misalignment?

    Jesse

    VLIB_Connected_Components_Labeling_idat.c

    results.txt

  • You are right, I tried to reproduce it for the same mask and failed.

    But the problem is still there , I putted a watch point at aligned image for memory write with 8 bit , vlaue = 103

    VLIB_createCCMap8Bit wrote this value for the following mask
    with minArea = 500,  (it should have at max value = 2 , just tow regions are bigger than 500)
    the problem occurs maybe due to low level optimizations or something like that.
    for a workaround, I just looped the aligned image and put zero whrere value > 10
    Can I help with additional information ? 
  • My system has timer inttrupt 2000 times / sec, maybe this affect the VLIB_createCCMap8Bit somehow ?
    The watchpoint triggered at VLIB_createCCMap8Bit  +  0x1B4

  • Mohammad,

    When the watchpoint triggered, was it within the VLIB_createCCMap8Bit function, or elsewhere?  If within this function, can you send me a snapshot of the dissasembly window showing the ASM code  (+/- several lines around the watchpoint trigger).

    Regarding the timer interrupt every half millisecond, that sounds like a lot to me.  I am not sure how this would affect the operation of this function unless something happening in the interrupt is corrupting the stack or some data.  If the watchpoint above is triggered outside of VLIB_createCCMap8Bit, then that should give your answer.

    Another thing you can try is to call the natural c version of the function to see if that gives a clue.  It may operate slower, but perhaps faster than the optimized version + your workaround: VLIB_createCCMap8Bit_cn.

    Jesse

  • Thanks, will try the c version on Monday (we have Eid al-Fitr here :) ) 

  • Here is a screenshot : (with watchpoint)

      

    memory map : 

    c14fd340    00000220     vlib.ae674 : VLIB_createCCMap8Bit.oe674 (.text:optimized)

    cn version :

    c14fd340    00000220     vlib_cn.ae674 : VLIB_createCCMap8Bit_cn.oe674 (.text)

  • Mohammad,

    I hope you had a good Eid al-Fitr.

    Thanks for sending your screenshots.  There are a few ideas I had when I saw them.

    1. I noticed that the watchpoint was triggered on LOAD instructions.  If the watchpoint tool is accurate (the imprecise word in the window makes me wonder if it is accurate), then this seems to mean that the memory is written because of a LOAD (READ) instruction.  Since this doesn't initially make sense, this makes me think about it being perhaps a cache-line eviction.  When a read request comes to a new cache line boundary, and it is a cache miss, then the cache line needs to be fetched from memory, while a different cache line needs to be evicted in order to make room.  If the cache is set to write-back policy, then this eviction may trigger a write back at that time before performing the cache line read.  Is it possible that there is some cache line boundary misalignment happening here?

    2. Is there some other DMA in the system that might be overwriting some cache/RAM boundary?

    3. Can you ensure that your  buffers are allocated according to multiples of cache lines (I think 32 bytes, but you should check the spec for your DSP).

    4. Could it be possible that there is some buffer overruns happening from other processes/tasks/interrupts that could be overwriting this memory such that when the cache line is evicted, it shows up back in the buffer?

    5. Perhaps try to narrow down the problem by either disabling the interrupts all-together, or at least disabling them while in this function (disable interrupts before entering the function, and re-enabling them after exiting this function).

    6. Perhaps try to narrow down the problem by disabling the cache to see if this gives any clues (this would probably slow things down too much, but may give some interesting data point if it happens still or not).

    It is difficult for me to debug this issue as it seems to be something specific to your full system setup since it is not reproducible in a simple stand-alone test, so the best I can do right now is offer some ideas for you to try out.

    Best Regards,

    Jesse

  • Will try those suggestions and let you know if I found something.

    Thanks.

  • Hey again,

    Sorry didn't have time to try what you suggested, but I think I have a reproducible masks now :  ( loop from first mask to third)

    first mask : 

    VLIB_createConnectedComponentsList(   handle, //  VLIB_CCHandle handle[26];
                                            im_size_x,
                                            im_size_y,
                                            (uint32_t *)input_image,
                                            min_blob_area,
                                            connectedCompFlag);
    im_size_x = im_size_y = 224
    min_blob_area = 10
    connectedCompFlag = 1
    then called : 
    VLIB_createCCMap8Bit(handle, aligned_image, im_size_x, im_size_y);  // aligned_mage  = 
    #pragma DATA_ALIGN(aligned_image, 0x20)
    unsigned char aligned_image[50176];

    Second Mask:

    VLIB_createConnectedComponentsList(   handle, //  VLIB_CCHandle handle[26];
                                            im_size_x,
                                            im_size_y,
                                            (uint32_t *)input_image,
                                            min_blob_area,
                                            connectedCompFlag);
    im_size_x = im_size_y = 224
    min_blob_area = 10
    connectedCompFlag = 1
    DIDN'T CALL  VLIB_createCCMap8Bit 

    Third Mask:

    VLIB_createConnectedComponentsList(   handle, //  VLIB_CCHandle handle[26];
                                            im_size_x,
                                            im_size_y,
                                            (uint32_t *)input_image,
                                            min_blob_area,
                                            connectedCompFlag);
    im_size_x = im_size_y = 224
    min_blob_area = 20
    connectedCompFlag = 1
    then called : 
    VLIB_createCCMap8Bit(handle, aligned_image, im_size_x, im_size_y);  // aligned_mage  = 
    #pragma DATA_ALIGN(aligned_image, 0x20)
    unsigned char aligned_image[50176];

    then I have  this result : (wrong values around row 76, col 7)

    Can you confirm the result please ?

  • Mohammad,

    I have been busy with a release this week so I haven't had time to look into this.  It takes some time for me to reconstruct your case above from scratch.  If you can reproduce this with a standalone unit test (perhaps using the one that comes in VLIB like I did last time), and pass the code to me (including file read or header file representation of input data), I should be able to work on this more quickly.  Please let me know.

    Jesse

  • Hey,
    I didn't understand whtat the problem with reconstructing the case (I gave you the input !)
     you can use this website to convert the bmp to array:

    https://littlevgl.com/image-to-c-array

    I use CCS3.3, I don't know much about the unit tests you use ..

    Thanks.

  • Thanks for the link.  This helped.  I have rerun the test you sent in the test framework that comes in VLIB.  I still can not reproduce the issue.

    One question.  Are you clearing the aligned_image before passing it to the VLIB_createCCMap8Bit function?  I don't see it in your code snippet above, but this needs to be done since the VLIB_createCCMap8Bit function is only writing the values from the blobs.  It doesn't overwrite the non-blob areas with 0s ... you need clear the whole buffer before calling this function.

    If you want to run the test on your side I have attached my changes to the idat and d files from the VLIB test.  You can simply replace these in the VLIB_Connected_Components_Labeling folder of VLIB, and recompile the test and load it into the bare metal C6 DSP and run in CCS.

    /*******************************************************************************
    **+--------------------------------------------------------------------------+**
    **|                            ****                                          |**
    **|                            ****                                          |**
    **|                            ******o***                                    |**
    **|                      ********_///_****                                   |**
    **|                      ***** /_//_/ ****                                   |**
    **|                       ** ** (__/ ****                                    |**
    **|                           *********                                      |**
    **|                            ****                                          |**
    **|                            ***                                           |**
    **|                                                                          |**
    **|         Copyright (c) 2007-2014 Texas Instruments Incorporated           |**
    **|                        ALL RIGHTS RESERVED                               |**
    **|                                                                          |**
    **| Permission to use, copy, modify, or distribute this software,            |**
    **| whether in part or in whole, for any purpose is forbidden without        |**
    **| a signed licensing agreement and NDA from Texas Instruments              |**
    **| Incorporated (TI).                                                       |**
    **|                                                                          |**
    **| TI makes no representation or warranties with respect to the             |**
    **| performance of this computer program, and specifically disclaims         |**
    **| any responsibility for any damages, special or consequential,            |**
    **| connected with the use of this program.                                  |**
    **|                                                                          |**
    **+--------------------------------------------------------------------------+**
    *******************************************************************************/
    
    #include "../common/VLIB_test.h"
    #include "../common/VLIB_memory.h"
    #include "../common/VLIB_profile.h"
    
    #include "VLIB_Connected_Components_Labeling.h"
    #include "VLIB_Connected_Components_Labeling_cn.h"
    #include "VLIB_Connected_Components_Labeling_idat.h"
    
    #include "AVMClasses.h"
    
    static void printHeader(uint32_t width)
    {
        uint32_t    i;
    
        for( i=0; i < width; i++ ) {
            printf("%d", (i / 10) % 10);
        }
    
        printf("\n  ");
    
        for( i=0; i < width; i++ ) {
            printf("%d", i % 10);
        }
    
        printf("\n +");
    
        for( i=0; i < width; i++ ) {
            printf("-");
        }
    }
    
    /*  P L E A S E    N O T E
    
    The primary function for grouping and labeling blobs in a binary image is
    VLIB_createConnectedComponentsList. The input to this function is a 32-bit
    packed binary image, e.g. foreground mask, and the output is a pointer to a
    "list" of 4- or 8-connected components (the list is actually a private
    structure). This pointer can be supplied to support functions, e.g.
    VLIB_getCCFeatures, VLIB_createCCMap8Bit, etc., so that meaningful
    information about the connected components can be extracted.
    
    For best performance, VLIB_createConnectedComponentsList should use internal
    and external memory buffers for processing the 32-bit packed binary
    foreground image (mask) and for storing the list of connected components.
    The amount of memory actually required is scene dependent.
    
    VLIB_createConnectedComponentsList is designed to use pPrimaryBuf1 and
    pPrimaryBuf2 memory buffers by internal, cache-enhanced double buffering.
    We recommend that pPrimaryBuf1 and pPrimaryBuf2 point to buffers in
    L1 Data and/or L2 Data memory for the best performance. During processing,
    the generated connected components are influenced by the image size and
    content. VLIB_createConnectedComponentsList uses pPrimaryBuf1 and
    pPrimaryBuf2 but will also consume memory in pOverflowBuf1 and
    pOverflowBuf2, as needed, after the primary buffers become exhausted.
    
    To be clear, all memory buffer assignments can use external DDR2 memory
    exclusively, but performance will be slower. It is illegal to supply null
    pointers as arguments to pPrimaryBuf1 or pPrimaryBuf2. Using the largest
    possible size for pPrimaryBuf1 and pPrimaryBuf2 is also recommended. It is
    appropriate to place pOverflowBuf1 and pOverflowBuf2 in external memory.
    Note: Make sure that the cache is enabled. Also be aware that overlapping
    memory buffers produces unknown results and is not recommended.
    
    In any case, the initialization function VLIB_initConnectedComponentsList
    must be called to identify the available memory buffers each time the addre
    changes, e.g. if persistent memory locations are available, only call the
    initialization function once in the beginning. These functions are not
    re-entrant.
    */
    
    /* VLIB_Connected_Components_Labeling_d:  Test Driver Routine */
    void VLIB_Connected_Components_Labeling_d (uint8_t LevelOfFeedback)
    {
        int32_t    tpi;//, j;  /* test parameter index */
        //FILE *f;
        //uint8_t *ptr;
        //uint8_t buff[50214];
        /* Test Parameters */
        ccl_testParams_t   *prm;
    
        ccl_getTestParams(&prm, &test_cases);
    
        /* Initialize profiling */
        VLIB_profile_init(2, "VLIB_Connected_Components_Labeling");
    #if 0
        f = fopen("file.pgm", "rb");
        if(f == NULL)
            printf("error\n");
        fread(&buff, 1, 50214, f);
        ptr = &buff[38];
        for(tpi=0;tpi<224; tpi++) {
            printf("\n");
            for(j=0;j<224; j++) {
                int tmp = ptr[tpi*224+j];
                tmp = (tmp > 0) ? 1 : 0;
                printf("%d, ", tmp);
            }
        }
    #else
    
        /* Run each test case */
        for( tpi = 0; tpi < test_cases; tpi++ ) {
    
            /* Initialize status flags */
            int32_t    status_numCCs = vlib_KERNEL_PASS;  /* Test status : Number of CCs compare to reference */
            int32_t    status_stats  = vlib_KERNEL_PASS;  /* Test status : Stats compare to reference */
            int32_t    status_mask   = vlib_KERNEL_PASS;  /* Test status : Mask compare to reference */
    
            /* Compute buffer sizes */
            uint32_t    inp_size =     prm[tpi].width * prm[tpi].height;
            uint32_t    packed_width = (prm[tpi].width + 31) / 32;
            uint32_t    mod_width    = packed_width * 32;                   /* Width must be a multiple of 32 */
            uint32_t    packed_size  = packed_width * prm[tpi].height;
            uint32_t    out_size =     mod_width * prm[tpi].height;
            int32_t     maxBytesRequired;
            int32_t     sizeOfCCHandle;
    
            /* Allocate buffers for each test vector */
            uint8_t         *input_image      =  (uint8_t *) malloc(inp_size * sizeof(uint8_t));
            uint32_t        *pIn32BitPacked   =  (uint32_t *) malloc(packed_size * sizeof(uint32_t));
            uint8_t         *pOutMap          =  (uint8_t *) malloc(out_size * sizeof(uint8_t));
            void            *pBuf;
            VLIB_CCHandle   *handle;
    
            /*
             * This function returns the bytes required to process the worst-case,
             * binary image, which is nearly impossible to occur in practice.
             * considers image dimensions as well the number and configuration of binary
             */
            VLIB_calcConnectedComponentsMaxBufferSize(prm[tpi].width, prm[tpi].height,
                                                      prm[tpi].minBlobArea,
                                                      &maxBytesRequired);
            pBuf    = (void *) malloc(maxBytesRequired);
    
            /*
             * The amount of memory required is content dependent.Since the pathological
             * condition is unlikely, especially if morphological functions are used to
             * remove or group small pixels, it is a good idea to shrink max bytes by
             * some factor, e.g. an order of magnitude.
             * maxBytesRequired = maxBytesRequired / 5;
             */
            sizeOfCCHandle =  VLIB_GetSizeOfCCHandle();
            handle = (VLIB_CCHandle *) malloc(sizeOfCCHandle);
    
            if( input_image && pIn32BitPacked && pOutMap && pBuf && handle ) {
    
                int32_t    fail, i, j;
                int32_t    status;
                int32_t    numCCs;
                VLIB_CC    vlibBlob;
    
                /* INITIALIZE FOREGROUND MASK AND MEMORY BUFFERS*/
                status  = VLIB_initConnectedComponentsList(handle, pBuf, maxBytesRequired);
    
                /* Fill input arrays according to desired test pattern */
                VLIB_fillBuffer(prm[tpi].testPattern,
                                (uint8_t)255,
                                input_image, prm[tpi].staticIn,
                                prm[tpi].width, prm[tpi].height, prm[tpi].width,
                                sizeof(uint8_t), testPatternString);
    
                /* In case input is not binary (rg. random input), mask out all bits except bit 0 */
                for( i=0; i < inp_size; i++ ) {
                    input_image[i] = (prm[tpi].testPattern == RANDOM) ? (input_image[i] & 1) : (input_image[i] > 0);
                }
    
                if( LevelOfFeedback > 0 ) {
                    printf("Input: %dx%d binary foreground mask:\n\n  ", prm[tpi].width, prm[tpi].height);
                    printHeader(prm[tpi].width);
                }
    
                /* Convert foreground symbols to a binary representation. */
                /* Binary foreground mask is packed into 32-bit word */
                memset(pIn32BitPacked, 0, packed_size * sizeof(int32_t));
                memset(pOutMap, 0, out_size);
    
                {
                    int32_t    j;
                    int32_t    fgMaskPixel;
                    int32_t    word, shift, pos;
                    int32_t    extra = (mod_width > prm[tpi].width);
    
                    for( j=0; j < prm[tpi].height; j++ ) {
                        shift = 31;
                        word  = 0;
                        pos   = 0;
                        if( LevelOfFeedback > 0 ) {
                            printf("\n%d|", j);
                        }
    
                        for( i=0; i < prm[tpi].width; i++ ) {
                            /* is this "pixel" location a member of the foreground? */
                            if( input_image[j * prm[tpi].width + i] > 0 ) {
                                if( LevelOfFeedback > 0 ) {
                                    printf("*");
                                }
                                fgMaskPixel = 1;
                            } else {
                                if( LevelOfFeedback > 0 ) {
                                    printf(" ");
                                }
                                fgMaskPixel = 0;
                            }
    
                            word |= (fgMaskPixel << shift);
    
                            if( shift == 0 ) {
                                pIn32BitPacked[j * packed_width + pos] = word;
                                pos++;
                                word                 = 0;
                                shift                = 31;
                            } else {
                                shift--;
                            }
                        }
    
                        if( extra ) {
                            pIn32BitPacked[j * packed_width + pos] = word;
                        }
                    }
                }
    
                fflush(stdout);
    
                if( LevelOfFeedback > 0 ) {
                    printf("\n\n ==== %d-connected component labeling ====",
                           (prm[tpi].connected8Flag + 1) * 4);
                }
    
                /* CONVERT FOREGROUND MASK INTO CONNECTED COMPONENTS*/
                VLIB_profile_start(vlib_KERNEL_OPT);
                status = VLIB_createConnectedComponentsList(handle,
                                                            mod_width,
                                                            prm[tpi].height,
                                                            pIn32BitPacked,
                                                            prm[tpi].minBlobArea,
                                                            prm[tpi].connected8Flag);
                VLIB_profile_stop();
    
                if( status == VLIB_WARNING_LOW_MEMORY ) {
                    printf("\nConnected Components low memory warning!!!!!\n");
                } else if( status != 0 ) {
                    VLIB_printErrCode(status);
                    printf("\nCreation of Connected Components failed!!!\n");
                    goto clean_exit;
                }
    
                /* REPORT FEATURES FROM CONNECTED COMPONENTS LIST*/
                VLIB_getNumCCs(handle, &numCCs);
    
                /* Report Items from List */
                if( LevelOfFeedback > 0 ) {
                    printf("\n\nIdentified %d connected-components with at least %d pixels:\n", numCCs, prm[tpi].minBlobArea);
                }
    
                if( prm[tpi].numCCs ) {
                    if( numCCs != prm[tpi].numCCs ) {
                        status_numCCs = vlib_KERNEL_FAIL;
                    }
                }
    
                /* Report CC Features */
                for( i=0; i < numCCs; i++ ) {
                    int32_t    left;
                    int32_t    right;
                    int32_t    top;
                    int32_t    bottom;
                    int32_t    xsum;
                    int32_t    ysum;
                    int32_t    area;
    
                    VLIB_getCCFeatures(handle, &vlibBlob, i);
    
                    left    = vlibBlob.xmin;
                    right   = vlibBlob.xmax;
                    top     = vlibBlob.ymin;
                    bottom  = vlibBlob.ymax;
                    xsum    = vlibBlob.xsum;
                    ysum    = vlibBlob.ysum;
                    area    = vlibBlob.area;
    
                    if( prm[tpi].staticOutStats && status_numCCs == vlib_KERNEL_PASS ) {
                        if( vlibBlob.xmin != prm[tpi].staticOutStats[i].xmin ||
                            vlibBlob.xmax != prm[tpi].staticOutStats[i].xmax ||
                            vlibBlob.ymin != prm[tpi].staticOutStats[i].ymin ||
                            vlibBlob.ymax != prm[tpi].staticOutStats[i].ymax ||
                            vlibBlob.xsum != prm[tpi].staticOutStats[i].xsum ||
                            vlibBlob.ysum != prm[tpi].staticOutStats[i].ysum ||
                            vlibBlob.area != prm[tpi].staticOutStats[i].area ) {
                            status_stats = vlib_KERNEL_FAIL;
                        }
                    }
    
                    if( LevelOfFeedback > 0 ) {
                        printf("Connected component #%d:\n", i + 1);
                        printf("  Pixel Area  : %d\n", area);
                        printf("  Bounding Box: left = %2d, right = %2d, top = %2d,bottom = %2d\n", left, right, top, bottom);
                        printf("  Horz. Sum   : %d\n", xsum);
                        printf("  Vert. Sum   : %d\n", ysum);
                        printf("  Centroid    : (%4.1f,%4.1f)\n\n", (VLIB_F32)xsum / area,
                               (VLIB_F32)ysum / area);
                    }
                }
    
                fflush(stdout);
    
                /* CREATE CONNECTED COMPONENTS MAP*/
                status = VLIB_createCCMap8Bit(handle,
                                              pOutMap,
                                              mod_width,
                                              prm[tpi].height);
    
                if( status != 0 ) {
                    VLIB_printErrCode(status);
                    printf("Creation of %d-bit Connected Components Map failed!!!\n",
                           (prm[tpi].connected8Flag + 1) * 4);
                    status_mask = vlib_KERNEL_FAIL;
                }
    
                /* DISPLAY CONNECTED COMPONENTS MAP*/
                if( LevelOfFeedback > 0 ) {
                    printf("Output: %dx%d binary foreground mask:\n\n  ", mod_width, prm[tpi].height);
                    printHeader(mod_width);
                }
    
                for( j=0; j < prm[tpi].height; j++ ) {
                    if( LevelOfFeedback > 0 ) {
                        printf("\n%d|", j);
                    }
    
                    for( i=0; i < mod_width; i++ ) {
                        if( prm[tpi].staticOut && pOutMap[j * mod_width + i] != prm[tpi].staticOut[j * prm[tpi].width + i] ) {
                            status_mask = vlib_KERNEL_FAIL;
                            if( LevelOfFeedback > 0 ) {
                                printf("X");
                            }
                        } else if( LevelOfFeedback > 0 ) {
                            printf("%d", pOutMap[j * mod_width + i]);
                        }
                    }
                }
    
                if( LevelOfFeedback > 0 ) {
                    printf("\n");
                }
    
    //////////////////////
    
                /* Fill input arrays according to desired test pattern */
                VLIB_fillBuffer(prm[tpi].testPattern,
                                (uint8_t)255,
                                input_image, &prm[tpi].staticIn[ prm[tpi].width * prm[tpi].height],
                                prm[tpi].width, prm[tpi].height, prm[tpi].width,
                                sizeof(uint8_t), testPatternString);
    
                /* In case input is not binary (rg. random input), mask out all bits except bit 0 */
                for( i=0; i < inp_size; i++ ) {
                    input_image[i] = (prm[tpi].testPattern == RANDOM) ? (input_image[i] & 1) : (input_image[i] > 0);
                }
    
                if( LevelOfFeedback > 0 ) {
                    printf("Input: %dx%d binary foreground mask:\n\n  ", prm[tpi].width, prm[tpi].height);
                    printHeader(prm[tpi].width);
                }
    
                /* Convert foreground symbols to a binary representation. */
                /* Binary foreground mask is packed into 32-bit word */
                //memset(pIn32BitPacked, 0, packed_size * sizeof(int32_t));
                //memset(pOutMap, 0, out_size);
    
                {
                    int32_t    j;
                    int32_t    fgMaskPixel;
                    int32_t    word, shift, pos;
                    int32_t    extra = (mod_width > prm[tpi].width);
    
                    for( j=0; j < prm[tpi].height; j++ ) {
                        shift = 31;
                        word  = 0;
                        pos   = 0;
                        if( LevelOfFeedback > 0 ) {
                            printf("\n%d|", j);
                        }
    
                        for( i=0; i < prm[tpi].width; i++ ) {
                            /* is this "pixel" location a member of the foreground? */
                            if( input_image[j * prm[tpi].width + i] > 0 ) {
                                if( LevelOfFeedback > 0 ) {
                                    printf("*");
                                }
                                fgMaskPixel = 1;
                            } else {
                                if( LevelOfFeedback > 0 ) {
                                    printf(" ");
                                }
                                fgMaskPixel = 0;
                            }
    
                            word |= (fgMaskPixel << shift);
    
                            if( shift == 0 ) {
                                pIn32BitPacked[j * packed_width + pos] = word;
                                pos++;
                                word                 = 0;
                                shift                = 31;
                            } else {
                                shift--;
                            }
                        }
    
                        if( extra ) {
                            pIn32BitPacked[j * packed_width + pos] = word;
                        }
                    }
                }
    
                fflush(stdout);
    
                if( LevelOfFeedback > 0 ) {
                    printf("\n\n ==== %d-connected component labeling ====",
                           (prm[tpi].connected8Flag + 1) * 4);
                }
    
                /* CONVERT FOREGROUND MASK INTO CONNECTED COMPONENTS*/
                VLIB_profile_start(vlib_KERNEL_OPT);
                status = VLIB_createConnectedComponentsList(handle,
                                                            mod_width,
                                                            prm[tpi].height,
                                                            pIn32BitPacked,
                                                            prm[tpi].minBlobArea,
                                                            prm[tpi].connected8Flag);
                VLIB_profile_stop();
    
                if( status == VLIB_WARNING_LOW_MEMORY ) {
                    printf("\nConnected Components low memory warning!!!!!\n");
                } else if( status != 0 ) {
                    VLIB_printErrCode(status);
                    printf("\nCreation of Connected Components failed!!!\n");
                    goto clean_exit;
                }
    
                /* REPORT FEATURES FROM CONNECTED COMPONENTS LIST*/
                VLIB_getNumCCs(handle, &numCCs);
    
                /* Report Items from List */
                if( LevelOfFeedback > 0 ) {
                    printf("\n\nIdentified %d connected-components with at least %d pixels:\n", numCCs, prm[tpi].minBlobArea);
                }
    
                if( prm[tpi].numCCs ) {
                    if( numCCs != prm[tpi].numCCs ) {
                        status_numCCs = vlib_KERNEL_FAIL;
                    }
                }
    
                /* Report CC Features */
                for( i=0; i < numCCs; i++ ) {
                    int32_t    left;
                    int32_t    right;
                    int32_t    top;
                    int32_t    bottom;
                    int32_t    xsum;
                    int32_t    ysum;
                    int32_t    area;
    
                    VLIB_getCCFeatures(handle, &vlibBlob, i);
    
                    left    = vlibBlob.xmin;
                    right   = vlibBlob.xmax;
                    top     = vlibBlob.ymin;
                    bottom  = vlibBlob.ymax;
                    xsum    = vlibBlob.xsum;
                    ysum    = vlibBlob.ysum;
                    area    = vlibBlob.area;
    
                    if( prm[tpi].staticOutStats && status_numCCs == vlib_KERNEL_PASS ) {
                        if( vlibBlob.xmin != prm[tpi].staticOutStats[i].xmin ||
                            vlibBlob.xmax != prm[tpi].staticOutStats[i].xmax ||
                            vlibBlob.ymin != prm[tpi].staticOutStats[i].ymin ||
                            vlibBlob.ymax != prm[tpi].staticOutStats[i].ymax ||
                            vlibBlob.xsum != prm[tpi].staticOutStats[i].xsum ||
                            vlibBlob.ysum != prm[tpi].staticOutStats[i].ysum ||
                            vlibBlob.area != prm[tpi].staticOutStats[i].area ) {
                            status_stats = vlib_KERNEL_FAIL;
                        }
                    }
    
                    if( LevelOfFeedback > 0 ) {
                        printf("Connected component #%d:\n", i + 1);
                        printf("  Pixel Area  : %d\n", area);
                        printf("  Bounding Box: left = %2d, right = %2d, top = %2d,bottom = %2d\n", left, right, top, bottom);
                        printf("  Horz. Sum   : %d\n", xsum);
                        printf("  Vert. Sum   : %d\n", ysum);
                        printf("  Centroid    : (%4.1f,%4.1f)\n\n", (VLIB_F32)xsum / area,
                               (VLIB_F32)ysum / area);
                    }
                }
    
                fflush(stdout);
    #if 0
                /* CREATE CONNECTED COMPONENTS MAP*/
                status = VLIB_createCCMap8Bit(handle,
                                              pOutMap,
                                              mod_width,
                                              prm[tpi].height);
    
                if( status != 0 ) {
                    VLIB_printErrCode(status);
                    printf("Creation of %d-bit Connected Components Map failed!!!\n",
                           (prm[tpi].connected8Flag + 1) * 4);
                    status_mask = vlib_KERNEL_FAIL;
                }
    
                /* DISPLAY CONNECTED COMPONENTS MAP*/
                if( LevelOfFeedback > 0 ) {
                    printf("Output: %dx%d binary foreground mask:\n\n  ", mod_width, prm[tpi].height);
                    printHeader(mod_width);
                }
    
                for( j=0; j < prm[tpi].height; j++ ) {
                    if( LevelOfFeedback > 0 ) {
                        printf("\n%d|", j);
                    }
    
                    for( i=0; i < mod_width; i++ ) {
                        if( prm[tpi].staticOut && pOutMap[j * mod_width + i] != prm[tpi].staticOut[j * prm[tpi].width + i] ) {
                            status_mask = vlib_KERNEL_FAIL;
                            if( LevelOfFeedback > 0 ) {
                                printf("X");
                            }
                        } else if( LevelOfFeedback > 0 ) {
                            printf("%d", pOutMap[j * mod_width + i]);
                        }
                    }
                }
    
                if( LevelOfFeedback > 0 ) {
                    printf("\n");
                }
    #endif
    
    //////////////////////
    
                /* Fill input arrays according to desired test pattern */
                VLIB_fillBuffer(prm[tpi].testPattern,
                                (uint8_t)255,
                                input_image, &prm[tpi].staticIn[prm[tpi].width * prm[tpi].height * 2],
                                prm[tpi].width, prm[tpi].height, prm[tpi].width,
                                sizeof(uint8_t), testPatternString);
    
                /* In case input is not binary (rg. random input), mask out all bits except bit 0 */
                for( i=0; i < inp_size; i++ ) {
                    input_image[i] = (prm[tpi].testPattern == RANDOM) ? (input_image[i] & 1) : (input_image[i] > 0);
                }
    
                if( LevelOfFeedback > 0 ) {
                    printf("Input: %dx%d binary foreground mask:\n\n  ", prm[tpi].width, prm[tpi].height);
                    printHeader(prm[tpi].width);
                }
    
                /* Convert foreground symbols to a binary representation. */
                /* Binary foreground mask is packed into 32-bit word */
                //memset(pIn32BitPacked, 0, packed_size * sizeof(int32_t));
                //memset(pOutMap, 0, out_size);
    
                {
                    int32_t    j;
                    int32_t    fgMaskPixel;
                    int32_t    word, shift, pos;
                    int32_t    extra = (mod_width > prm[tpi].width);
    
                    for( j=0; j < prm[tpi].height; j++ ) {
                        shift = 31;
                        word  = 0;
                        pos   = 0;
                        if( LevelOfFeedback > 0 ) {
                            printf("\n%d|", j);
                        }
    
                        for( i=0; i < prm[tpi].width; i++ ) {
                            /* is this "pixel" location a member of the foreground? */
                            if( input_image[j * prm[tpi].width + i] > 0 ) {
                                if( LevelOfFeedback > 0 ) {
                                    printf("*");
                                }
                                fgMaskPixel = 1;
                            } else {
                                if( LevelOfFeedback > 0 ) {
                                    printf(" ");
                                }
                                fgMaskPixel = 0;
                            }
    
                            word |= (fgMaskPixel << shift);
    
                            if( shift == 0 ) {
                                pIn32BitPacked[j * packed_width + pos] = word;
                                pos++;
                                word                 = 0;
                                shift                = 31;
                            } else {
                                shift--;
                            }
                        }
    
                        if( extra ) {
                            pIn32BitPacked[j * packed_width + pos] = word;
                        }
                    }
                }
    
                fflush(stdout);
    
                if( LevelOfFeedback > 0 ) {
                    printf("\n\n ==== %d-connected component labeling ====",
                           (prm[tpi].connected8Flag + 1) * 4);
                }
    
                /* CONVERT FOREGROUND MASK INTO CONNECTED COMPONENTS*/
                VLIB_profile_start(vlib_KERNEL_OPT);
                status = VLIB_createConnectedComponentsList(handle,
                                                            mod_width,
                                                            prm[tpi].height,
                                                            pIn32BitPacked,
                                                            20,
                                                            prm[tpi].connected8Flag);
                VLIB_profile_stop();
    
                if( status == VLIB_WARNING_LOW_MEMORY ) {
                    printf("\nConnected Components low memory warning!!!!!\n");
                } else if( status != 0 ) {
                    VLIB_printErrCode(status);
                    printf("\nCreation of Connected Components failed!!!\n");
                    goto clean_exit;
                }
    
                /* REPORT FEATURES FROM CONNECTED COMPONENTS LIST*/
                VLIB_getNumCCs(handle, &numCCs);
    
                /* Report Items from List */
                if( LevelOfFeedback > 0 ) {
                    printf("\n\nIdentified %d connected-components with at least %d pixels:\n", numCCs, 20);
                }
    
                if( prm[tpi].numCCs ) {
                    if( numCCs != prm[tpi].numCCs ) {
                        status_numCCs = vlib_KERNEL_FAIL;
                    }
                }
    
                /* Report CC Features */
                for( i=0; i < numCCs; i++ ) {
                    int32_t    left;
                    int32_t    right;
                    int32_t    top;
                    int32_t    bottom;
                    int32_t    xsum;
                    int32_t    ysum;
                    int32_t    area;
    
                    VLIB_getCCFeatures(handle, &vlibBlob, i);
    
                    left    = vlibBlob.xmin;
                    right   = vlibBlob.xmax;
                    top     = vlibBlob.ymin;
                    bottom  = vlibBlob.ymax;
                    xsum    = vlibBlob.xsum;
                    ysum    = vlibBlob.ysum;
                    area    = vlibBlob.area;
    
                    if( prm[tpi].staticOutStats && status_numCCs == vlib_KERNEL_PASS ) {
                        if( vlibBlob.xmin != prm[tpi].staticOutStats[i].xmin ||
                            vlibBlob.xmax != prm[tpi].staticOutStats[i].xmax ||
                            vlibBlob.ymin != prm[tpi].staticOutStats[i].ymin ||
                            vlibBlob.ymax != prm[tpi].staticOutStats[i].ymax ||
                            vlibBlob.xsum != prm[tpi].staticOutStats[i].xsum ||
                            vlibBlob.ysum != prm[tpi].staticOutStats[i].ysum ||
                            vlibBlob.area != prm[tpi].staticOutStats[i].area ) {
                            status_stats = vlib_KERNEL_FAIL;
                        }
                    }
    
                    if( LevelOfFeedback > 0 ) {
                        printf("Connected component #%d:\n", i + 1);
                        printf("  Pixel Area  : %d\n", area);
                        printf("  Bounding Box: left = %2d, right = %2d, top = %2d,bottom = %2d\n", left, right, top, bottom);
                        printf("  Horz. Sum   : %d\n", xsum);
                        printf("  Vert. Sum   : %d\n", ysum);
                        printf("  Centroid    : (%4.1f,%4.1f)\n\n", (VLIB_F32)xsum / area,
                               (VLIB_F32)ysum / area);
                    }
                }
    
                fflush(stdout);
    
                /* CREATE CONNECTED COMPONENTS MAP*/
                status = VLIB_createCCMap8Bit(handle,
                                              pOutMap,
                                              mod_width,
                                              prm[tpi].height);
    
                if( status != 0 ) {
                    VLIB_printErrCode(status);
                    printf("Creation of %d-bit Connected Components Map failed!!!\n",
                           (prm[tpi].connected8Flag + 1) * 4);
                    status_mask = vlib_KERNEL_FAIL;
                }
    
                /* DISPLAY CONNECTED COMPONENTS MAP*/
                if( LevelOfFeedback > 0 ) {
                    printf("Output: %dx%d binary foreground mask:\n\n  ", mod_width, prm[tpi].height);
                    printHeader(mod_width);
                }
    
                for( j=0; j < prm[tpi].height; j++ ) {
                    if( LevelOfFeedback > 0 ) {
                        printf("\n%d|", j);
                    }
    
                    for( i=0; i < mod_width; i++ ) {
                        if( prm[tpi].staticOut && pOutMap[j * mod_width + i] != prm[tpi].staticOut[j * prm[tpi].width + i] ) {
                            status_mask = vlib_KERNEL_FAIL;
                            if( LevelOfFeedback > 0 ) {
                                printf("X");
                            }
                        } else if( LevelOfFeedback > 0 ) {
                            printf("%d", pOutMap[j * mod_width + i]);
                        }
                    }
                }
    
                if( LevelOfFeedback > 0 ) {
                    printf("\n");
                }
    
    
    ///////////////////////
    
                /* Set the 'fail' flag based on test vector comparison results */
                fail = ((status_numCCs == vlib_KERNEL_FAIL) ||
                        (status_stats == vlib_KERNEL_FAIL) ||
                        (status_mask == vlib_KERNEL_FAIL)) ? 1 : 0;
    
                est_test=1;
    
                /* Profile display and preparation for cycle estimation */
                sprintf(desc, "%s generated input | Opt results compared to static results | width=%d, height=%d, minBlobArea=%d, connected8Flag=%d, numCCs=%d",
                        testPatternString, prm[tpi].width, prm[tpi].height, prm[tpi].minBlobArea, prm[tpi].connected8Flag, numCCs);
                VLIB_formula_add_test(out_size, NULL, NULL, fail, desc, NULL);
    
            } else {
                /* Display the error printout for this test vector before moving on to the next test vector */
                sprintf(desc, "width=%d, height=%d, minBlobArea=%d, connected8Flag=%d",
                        prm[tpi].width, prm[tpi].height, prm[tpi].minBlobArea, prm[tpi].connected8Flag);
                VLIB_skip_test(desc);
            }
    
    clean_exit:
            /* Free buffers for each test vector */
            free(handle);
            free(pBuf);
            free(pOutMap);
            free(pIn32BitPacked);
            free(input_image);
        }
    
        /* Calculate and display cycle formula and/or cycle range (and testing success) */
        VLIB_profile_cycle_report(vlib_PROFILE_RANGE,
                                  NULL,
                                  "CELING(width,32) * height");
    
        /* Provide memory requirements */
        VLIB_kernel_memory();
        #endif
    }
    
    /* Main call for individual test projects */
    #ifndef __ONESHOTTEST
    
    main() {
        if( VLIB_cache_init()) {
            VLIB_memError("VLIB_Connected_Components_Labeling");
        } else {
            VLIB_Connected_Components_Labeling_d(1);
        }
    }
    #endif /* __ONESHOTTEST */
    
    /* ======================================================================== */
    /*  End of file:  VLIB_Connected_Components_Labeling_d.c                    */
    /* ======================================================================== */
    
    

    8117.VLIB_Connected_Components_Labeling_idat.c

  • Of course, We clean the aligned_image ...

    Can you please explain what this line do :

    VLIB_profile_start(vlib_KERNEL_OPT);

    We don't use it in our code ..

  • I think the bug is related to some uninitialized variable.

    If I run the functions below on those 4 masks, it will work Ok for the first 3, then it will put wrong values at the forth mask.

    If I rerun the test, it will put wrong values at the FIRST mask (until I exit CCS3 and enter again)

    (ran this function once)
    VLIB_initConnectedComponentsList(
    handle,
                    scratchPad_0,
                    MAX_CONNECTED_COMPONENTS_BYTES
    );
    VLIB_createConnectedComponentsList(   handle, //  VLIB_CCHandle handle[26];
                                            im_size_x,
                                            im_size_y,
                                            (uint32_t *)input_image,
                                            min_blob_area,
                                            connectedCompFlag);
    im_size_x = im_size_y = 224
    min_blob_area = 10
    connectedCompFlag = 1
    then called : 
    VLIB_createCCMap8Bit(handle, aligned_image, im_size_x, im_size_y);  // aligned_mage  = 
    #pragma DATA_ALIGN(aligned_image, 0x20)
    unsigned char aligned_image[50176];
    Can you please check with those masks? (I tried to use your files but didn't success :( ).
  • Mohammad Dahamshi said:

    Can you please explain what this line do :

    VLIB_profile_start(vlib_KERNEL_OPT);

    This is for test purposes to record the timer and markup the stack so that we can profile how long the operation takes and how deep the stack goes.  For production SW, this should not be used.

  • Can you please check with the provided masks ? bleow is the functions I used:
    VLIB_createConnectedComponentsList(   handle, //  VLIB_CCHandle handle[26];
                                            im_size_x,
                                            im_size_y,
                                            (uint32_t *)input_image,
                                            min_blob_area,
                                            connectedCompFlag);
    im_size_x = im_size_y = 224
    min_blob_area = 10
    connectedCompFlag = 1
    then called : 
    VLIB_createCCMap8Bit(handle, aligned_image, im_size_x, im_size_y);  // aligned_mage  = 
    #pragma DATA_ALIGN(aligned_image, 0x20)
    unsigned char aligned_image[50176];
  • Can you please run the functions on random input and then check :
    for(x = 0; x < 224 * 224 ; x++)
    if(aligned_image[x] > number of found blobs)
    {
    breakpoint here
    }

    So you can find when this bug happens ?
  • Okay, this test was a good suggestion.  With it I was able for the first time to reproduce your problem and see the failure.  I will spend some time on this tomorrow to debug and find the source of the problem

    Thanks,.

    Jesse

  • Mohammad,

    I was able to find the root cause and resolve the issue. I can work on getting an updated release next week. Before I do, I was wanting to check if your project would have issues linking the library compiled against C6000 compiler version 8.2.4, as we have been updating our latest releases to use this. I'm not sure which compiler version you are using and if version 8.2.x would work okay for you.

    Also, is your production code using the VLIB_createCCMap8Bit function? If so, is the speed working for you for this function? Our unit test monitors the performance of the VLIB_createConnectedComponentsList function, but up until now, not the VLIB_createCCMap8Bit.
  • 1. We use C6000 v7.4.19 compiler, but We already used the latest VLIB with it with no problems.
    2. Yes we do, the speed isn't that good (it takes around 0.5 M to 1.5 M cyles, although it uses the handle VLIB_createConnectedComponentsList used, it should take less since you already looped the mask, maybe it is better to merge the two functions ?). We are thinking about building our own.
  • Hey

    When will you send an update ? (you said next week..)

    I checked here 

  • I ran into some build/packaging issues that delayed me but I got past them over the weekend. I expect it to be out in next few days.

    Jesse
  • Do you a workaround until the update is available ? (my workaround work well to avoid memory corruption, but there still wrong id's for blobs)

  • The update just went live on the website you mentioned above. Please download and try it out. This also has a few other fixes in other functions from 3.3.1.0 (internal release).
  • just small notice, your site may have some problems in caching, I had to force reload (ctrl + f5) to get the new page with new release..

  • We succeded to link to the 3_3_2_0 new lib with compiler 8.0.4
    but we failed with v7.4.19 (although we succeded with vlib 3_3_0_3)
    Can you help please ?
  • The compiler version 7.x supported both COFF and ELF ABI formats.  However, the compiler version 8.x supports only ELF ABI.  Can you confirm if your program compiled using 7.x is using ELF ABI?  The library and the linking program should both be using same (ELF) ABI.

    Jesse

  • No it uses COFF ABI, I noticed that in version 3_3_0_3 you provied vlib.a674 (which I assume belong to COFF ABI) but in last version you didn't.
    So can you please provied the COFF ABI please ?
  • In 3_3_0_3, the compiler version used was 7.4.2 which supported both elf and coff, and so for c674 version, we delivered both elf and coff. In 3.3.2.0, the compiler version used was 8.2.4, which no longer supports coff, only elf. Therefore I can not provide a coff version for this compiler. Is there a reason why you need COFF in your program, or can you change to use elf (EABI) in your program?

    If you need more details on the implications of this, you can look at following document:
    C6000 Embedded Application Binary Interface: www.ti.com/lit/an/sprab89a/sprab89a.pdf
  • Yes there are, We use 64 MB from the ram as a usb drive, when We compile the usblib (from C6748_StarterWare_1_20_04_01) with the new compiler (ELF) , it compiles fine, but it doesn't work (we don't see mass storage device in the pc)
  • Okay, I understand. Let me see if I can revert the compiler and config to generate old compiler version for you. It will take between 1 and 2 days, I suspect.
  • Mohammad,

    We have uploaded the release built with the legacy compiler. Please refresh the release page, and see the Compatibility Note and associated link that was added.

    Jesse