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.

Recompiling and using updated RTS library

Other Parts Discussed in Thread: CCSTUDIO

I'm having issues with the implementation of malloc()/free() prodvided by TI.  The implementation found in the RTS library that comes with Code Generation Tools seems less than optimal, so I'm trying to modify them.  I've figure out how to extract the source files, make my modification, and then gmake to rebuild the desired library (rts6400e.lib, C6416 part, big endian, no exception handling).  However, I can't seem to figure out how to actually use that library.  My project currently links against csl6416e.lib for the chip-support library related items.  But if I link against csl6416e.lib, I can't also link against my rebuilt rts6400e.lib.  So do I need to modify and rebuild csl6416e.lib?  If so, how?  If not, what am I doing wrong?  Thanks.

  • You can link from as many libraries as you want to. Since the malloc()/free() functions should not be found in csl6416e.lib, you are already linking from some rts6400e.lib file, just not the one you want to.

    Eventually, the libraries all get specified in the linker command file(s). DSP/BIOS or CCS may have "hidden" ways that they specify the rts lib to use, and that could make it a little harder to find or modify. But there are ways around anything.

    Which versions of CCS and DSP/BIOS and Code Generation tools are you using?

    A generalized method to do what you want may require a little reading in the Compiler User's Guide and/or the Assembly Language Tools User's Guide. But one way to do what you want, in spite of the other tools, is this:

    1. Create a new, short, user-generated linker command file, like MyLinker.cmd. In it put one line that says to include the rts library file that you have re-built. The ALT UG will have the exact syntax, but it is something like -l c:\<path>\rts6400e.lib. It might be -i instead and there may or may not be a space after the command.
    2. Add MyLinker.cmd to your project.
    3. In the project Build Properties, probably for the linker, there will be a Link Order place where you can tell it to use your linker command file before all the others by setting its link order to 1 and the others to 2 or more. If some of the linker command files are not specifically in the project, do not worry about them - they get pulled in by one of the other linker command files.

    An easier way to do what you want to do is to forget about changing the library and just add your malloc()/free() source files to the project. They should get picked up and built and linked before any libraries. This would not give you the convenience of porting your improvements to other projects by just carrying the lib around, but it would work.

    What things did you change to make it optimum? There is a different version in DSP/BIOS, so maybe it has some different features. You can check the BIOS User's Guide or API Reference Guide to find out.

  • Using Code Composer Studio 3.3 and Code Generation Tools v6.1.7.

    If I add both csl6416e.lib and rts6400e.lib to the list of libraries to include [found under: Build Options-> Linker-> Libraries-> Incl. Libraries (-l)], I get the following linker errors:

    error #10056: symbol "_c_int00" redefined: first defined in "C:/Program
       Files/C6000Code Generation Tools 6.1.7/lib/rts6400e.lib<boot.obj>";
       redefined in
       "C:/CCStudio_v3.3/bios_5_31_02/packages/ti/bios/lib/bios.a64e<boot.o64e>"
    error #10056: symbol "__stack" redefined: first defined in "C:/Program
       Files/C6000Code Generation Tools 6.1.7/lib/rts6400e.lib<boot.obj>";
       redefined in
       "C:/CCStudio_v3.3/bios_5_31_02/packages/ti/bios/lib/bios.a64e<boot.o64e>"
    warning #10210-D: creating ".sysmem" section with default size of 0x400; use
       the -heap option to change the default size
    error #10010: errors encountered during linking; "./Debug/MyProject.out" not
       built

    >> Compilation failure

     

    I'm using a *.tcf file which, I believe, generates my linker *.cmd file.  In that file I see:

    -priority
    --trampolines
    -llnknone.a64e
    -ldrivers.a64e         /* device drivers support */
    -lsioboth.a64e         /* supports both SIO models */
    -lbiosC6000.a64e       /* BIOS clock specific library */
    -lbios.a64e            /* DSP/BIOS support */
    -lrts6400e.lib         /* C and C++ run-time library support */

    which I can only assume is where the rts6400e.lib is being pulled in.  Do I just need to re-order the priority here so it takes the rts6400e.lib version instead of the bios.a64e version?  Where can I find the bios.a64e version?  How would I change that one?  The changes I'm making to malloc()/free() in the rts6400e.lib are not taking affect when I run my program.  (As a test, I hardcoded the return values of these methods to make sure it's working, and the behavior of malloc()/free() did not change).

    Simply over-riding malloc()/free() in a project source file would work just fine, but I'm not sure how to do that.  The RTS 'memory.c' file uses some data structures and defines (PACKET, BLOCK_MASK, etc) and global static variables (sys_free, _sys_memory) that I'm not sure how to access those I try to over-ride malloc()/free() in a C source file added to the project.  Is there any documentation that describes how to do it?

    You say there is a different version in DSP/BIOS.  Do you mean a different version of malloc()/free()?  Where can I view their source?

    As an example of how the RTS lib versions are less than optimum, look at free().  If the previous and next blocks are already freed and can be collesced, it searches the entire free list for each the previous and next block when it already has them.  free() overall can do up to 4 linear, O(n) complexity, searches through the free list.  If there is a lot of memory fragmentation (frequently causing both the previous and next blocks to be free already) and many small objects being allocated (resulting in a long search through the free-list), free() can start taking a long amount of time.  This ends up making a time critical section of our code go from an initial 300us to over 1ms after about 100 iterations (with ~40 delete's/free() calls per iteration).

    Thanks for your feedback so far.

  • If this goes beyond my knowledge, the BIOS Forum is the best place to find the folks who will know. Basically, you want to override the rts library that DSP/BIOS chooses.

    I am a hacker-type of user of these things, and try the things like I suggested above. But there may be answers addressing this in the DSP/BIOS User's Guide. One of the BIOS experts might point you to an exact place, but I can at least point you to the documentation.

    Another idea that might work would be to add another library search path to the linker's setup so it would find yours first. But the error message you are getting tells me that the rts lib that BIOS uses is slightly modified from the one that comes with the compiler tools. I have had this same error in the past, but it was because I did not know BIOS already included it or because I added BIOS to a non-BIOS project. Long story, no help.

    When you compile and archive files into the library, my recollection is that everything in each C file becomes part of a single module. Whenever any function or symbol within that module is required by the linker, the entire module is linked in. So your separate file solution would be to use your own copy of memory.c so that everything in it is resolved.

    DSP/BIOS implements MEM_alloc()/MEM_free() functions that let you specify any of multiple heaps to use for the allocation. Any calls to malloc()/free() or new/delete will use the rts version, but you can specify MEM_alloc() to instead specify any heap. You have to tell BIOS, through the System->Memory allocations, to allocate a heap in any memories where you want to have one.

    Mark Jansen said:
    This ends up making a time critical section of our code go from an initial 300us to over 1ms after about 100 iterations (with ~40 delete's/free() calls per iteration).

    Wow. That is a big increase. Your changes are optimized for your application, I guess. I am not sure that in a purely random situation that it would average being faster to look nearby in the list before starting from the head, but that might be an arguable point. An interesting point, at the very least.

  • Randyp said:
    Wow. That is a big increase. Your changes are optimized for your application, I guess. I am not sure that in a purely random situation that it would average being faster to look nearby in the list before starting from the head, but that might be an arguable point. An interesting point, at the very least.

    It's not a matter of checking adjacent blocks first before searching through the free list.  It never should need to search through the free list as when it collesces blocks, it only ever collesces adjacent blocks in the list.  The function already has access to the previous and next blocks, but does a linear search for each of them again for no apparent reason, increasing the maximum number of linear searches for blocks from 2 to 4.  Once to search for the initial block to free, once to insert the freed block back into the free list when it's all done, and once or twice more to collesce either the next or previous blocks, or both next and previous blocks.  The final 1-2 searches are completely unnecessary..

     

    I think I've narrowed my issues down to the *.cmd file.  Here's the relevant section again:

    -priority
    --trampolines
    -llnknone.a64e
    -ldrivers.a64e         /* device drivers support */
    -lsioboth.a64e         /* supports both SIO models */
    -lbiosC6000.a64e       /* BIOS clock specific library */
    -lbios.a64e            /* DSP/BIOS support */
    -lrts6400e.lib         /* C and C++ run-time library support */

    If I attempt to swap the order of the "bios.a64e" and "rts6400e.lib" includes, I get the error:

    <Linking>
    error #10056: symbol "_c_int00" redefined: first defined in "C:/Program
       Files/C6000Code Generation Tools 6.1.7/lib/rts6400e.lib<boot.obj>";
       redefined in
       "C:/CCStudio_v3.3/bios_5_31_02/packages/ti/bios/lib/bios.a64e<boot.o64e>"
    error #10056: symbol "__stack" redefined: first defined in "C:/Program
       Files/C6000Code Generation Tools 6.1.7/lib/rts6400e.lib<boot.obj>";
       redefined in
       "C:/CCStudio_v3.3/bios_5_31_02/packages/ti/bios/lib/bios.a64e<boot.o64e>"
    warning #10210-D: creating ".sysmem" section with default size of 0x400; use
       the -heap option to change the default size
    error #10010: errors encountered during linking; "./Debug/MyProject.out" not
       built

    >> Compilation failure

    I'll start reading up some more on BIOS projects...

  • Mark Jansen said:
    It's not a matter of checking adjacent blocks ...

    That is very inefficient to not take advantage of the doubly-linked list of sorted-by-address items. I am not sure what other purpose there would be for having a doubly-linked list other than to make the coalescing easier and quicker. Once you get this working, please consider posting your solution, including the memory.c file and your procedure for rebuilding and using the rts lib, here or to a Wiki page. Many others would find it useful, and maybe we can get it incorporated into the release library - I have no say or input into that, so results may vary.

    Mark Jansen said:
    I think I've narrowed my issues down to the *.cmd file....

    I am a bit confused over the status of the swap vs. the inclusion of your new rts lib in a separate linker command file. The file you are excerpting from is generated by BIOS and you do not want to be modifying it.

    But, rather than doing more explaining, try this first. In CCS 3.3, open the GUI for your tcf file, expand the System group and right-click to Properties on Global Settings. One of the check boxes is Specify RTS library; click that and put in the full path to your rts6400e.lib (or use a name it will not find earlier in the lib search and add that path to the linker's library search paths). If that works, send me back an upper-case duh.

  • RandyP said:
    That is very inefficient to not take advantage of the doubly-linked list of sorted-by-address items.

    The memory management used in the RTS library for free(), malloc(), etc, uses a singlely-linked list.

    I'm excerpting from the generated *.cmd file generated by BIOS via the *.tcf file.

    I tried doing as you said, but the generated *.cmd file doesn't change (it was already using the desired rts6400e.lib, even if it's not pulling in the malloc()/free() from it.).

    I looked at the PDF file you sent, lib_ref_order[1].pdf, which explains why I can't swap the order order of the BIOS and RTS library in the *.cmd file.  But that means it always takes the malloc() from the BIOS library, bios.a64e, instead of rts6400e.lib.  So any changes I make to malloc() in the rts library are not used.

    So my question boils down to: 1) how can I view/modify the BIOS library versions of malloc()/free(), etc or 2) how do I force it to accept the malloc()/free(), etc in the RTS library under a BIOS project?

  • Mark Jansen said:
    I looked at the PDF file you sent, lib_ref_order[1].pdf

    I had to look for the file that we sent to you and found the thread here that had the presentation you were looking at. The last bullet on the last page says

    lib_ref_order.pdf said:
    BIOS libs redefining the memory allocation routines malloc/free. Those calls always need to be resolved from the BIOS lib, and then the compiler RTS lib.

    This implies to me that the malloc/free used by BIOS are different than what you get in the rts lib. And that then means that you will be taking a big chance by doing a blanket replacement with your modified malloc/free. I have no idea what BIOS needs different, but the statement above says "malloc/free...always need to be resolved from the BIOS lib", and Georgem knows what he is talking about even if I do not know what he is talking about.

    You and I cannot get to source code for BIOS to figure out what it does differently, I think your most realistic choice is to change the name of your malloc/free functions and call your own. This will leave the library version for BIOS's use and you can make your own optimized accesses using your functions. Not an ideal solution but what do you think?

  • Have you looked at the BUF module?

    Pros

    • Deterministic/constant times for doing alloc/free
    • Callable from all thread types
    • Doesn't fragment

    Cons

    • Fixed length buffers

     

  • Not an option, for two reasons.  1) The code base is common with other platforms.  In this particular instance, a PowerPC environment.  2) Fixed length buffers would consume too much memory.  The data flow through the system is fairly consistent overall, but what does vary is the number of packets and their size.  I can get extremes of few, large packets or many, small packets.  I do not have enough memory for the many, large packets that would be required for using fixed length buffers.

  • Brad beat me to this, I was going to suggest the BIOS BUF module. This is exactly what it was designed for. Quick, deterministic allocation and freeing of buffers.

    One item to note, while the buffers are of fixed length (which BTW, helps to minimize fragmentation), you can create as many different groups of buffers - for each group of buffers, you can specify the:

    • Number of buffers
    • Size of buffers
    • Alignment
    • Location (in memory map)

    It's one of the hidden gems in BIOS, and quite simple to use!

    Scott

  • As I stated before, breaking away from using 'new' and 'delete' will make the code base completely unportable, which is not really an option for me.  Also, I do not have the memory to allocate sufficient fixed length buffers to cover all of my use cases (many, small packets and few, large packets).

  • Mark Jansen said:
    As I stated before, breaking away from using 'new' and 'delete' will make the code base completely unportable, which is not really an option for me.

    No problem!  Add a file to your project called malloc.c which defines malloc().  This function will be resolved first by the linker and so it will override the version in BIOS (just as BIOS was overriding the RTS library).  You can define this function to make calls into BUF_alloc().

    Mark Jansen said:
    Also, I do not have the memory to allocate sufficient fixed length buffers to cover all of my use cases

    If you create several BUF pools the amount of "waste" will be reduced.  For example, you could create 4 or 8 different pools.  Your implementation of malloc would consist of a binary search for the right size pool (i.e. 2 or 3 "if" statements) followed by the BUF_alloc to the appropriate pool.

    How much SDRAM do you have?  Have you considered going a size bigger?

    Mark Jansen said:
    (many, small packets and few, large packets)

    Although determinism is your issue now, you may very well run into fragmentation issues later.  BUF_alloc solves both!

    So it looks like the bottom line is that you need to write your own "malloc" and "free" functions.  I personally would make every effort to use BUF_alloc.  If you don't think that works for you then your other option is to utilize code shipped with rts6416 to create your own malloc function.  Even if you make it more efficient you will still have an issue with non-determinism (i.e. it will grow by 'n' instead of '2n').  Maybe that's good enough, but if you have many mallocs happening that might get ugly.

  • I'm currently in the process of testing a new memory manager to replace the calls to the bios malloc()/free() methods.  The overhead per allocation is higher (16 bytes vs. 8 bytes), and has slightly worse performance on un-fragmented memory, but has an order of magnitude better performance when memory becomes fragmented.  Under load, I've counted (via overridden new/delete) a maximum of ~2800 dynamically allocated memory blocks.  This equates to 22.4 kBytes of extra overhead versus the bios malloc()/free(), which I can handle.

    My memory constraint is high because I keep all data in ISRAM.  The code is loaded into SDRAM with 256kB cache enabled for the SDRAM.  I can't afford the time it takes to share the cache between code and data.

    My test scenario consists of allocating 1,000 ints, then deleting every other allocation.  This creates 500 unallocated memory segments.  (In my system, I end up with ~600 free segments when things fall apart).  Next is allocating three objects larger than an int, and then deleting them in the order of first, third, and second.  Using the profilier Clock, I get 14,333 ticks using the default malloc()/free(), and 1,141 ticks using my new manager.  I'm going to have to thoroughly test the manager and drop it in the system to see how well it works in practice.