This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

memory optimizations

Hello,

I write code C using C51 for DP8051 (of DCD).
I start to experience problem with the too small 256-bytes internal memory.
It seems that when adding an automatic idata variables (function-internal) even to functions that are never called, the number of bytes used in the idata memory grows.
I have read some information about the fact that the compiler will not use stack, and instead will choose which variables it can overlay on the same memory locations. I still think that if a function is never called then another parameter in it should not change the number of idata bytes used. I have also found that adding automatic idata variables to some functions will change the number of used idata bytes (after compile and build) while adding the same variable to another function may not change the used idata bytes after compilation. this is expected, but still is like a mist to me, since I don't have the knoledge that will help me to get the best out of the comiler.
The following code demonstrates what I saw:

static void Cmd_parser_write (UINT8 DPP_megablock, UINT16 write_addr, UINT8 write_value)
{
	UINT8 idata DPP_save_val = DPP;
//	UINT8 idata temp_memcheck0;// ### remove this comment
//	UINT8 idata temp_memcheck1;// ### remove this comment
	DPP = DPP_megablock;
	XBYTE[write_addr] = write_value;
	DPP = DPP_save_val;
} /* end of Cmd_parser_write */

static void Cmd_parser_read (UINT8 DPP_megablock, UINT16 read_addr, UINT8 DPP_storage, UINT16 storage_addr)
{
	UINT8 idata DPP_save_val = DPP;
	UINT8 idata data_read;
//	UINT8 idata temp_memcheck0;// ### remove this comment
//	UINT8 idata temp_memcheck1;// ### remove this comment

	DPP = DPP_megablock;
	data_read = XBYTE[read_addr];
	DPP = DPP_storage;
	XBYTE[storage_addr] = data_read;
	DPP = DPP_save_val;
} /* end of Cmd_parser_read */
when unmarking temp_memcheck0 from Cmd_parser_write function the memory size will not change, while when unmarking this variable from Cmd_parser_read function the size if internal data grows.


I would like to get explanation about the way that the compiler analyze the code and choose which variables can be overlaid, in order to write more efficient code that will consume as less idata memory as possible, and leave as much memory as possible for the stack. Will the compiler cross files in this kind of optimization ?
Another question in the same issue:
While looking at the map file, is see the following:
            TYPE    BASE      LENGTH    RELOCATION   SEGMENT NAME
            -----------------------------------------------------

            * * * * * * *   D A T A   M E M O R Y   * * * * * * *
            REG     0000H     0008H     ABSOLUTE     "REG BANK 0"
            REG     0008H     0008H     ABSOLUTE     "REG BANK 1"
            REG     0010H     0008H     ABSOLUTE     "REG BANK 2"
            DATA    0018H     0008H     UNIT         ?DT?C2C_IF_DRIVER
            BIT     0020H.0   0001H.1   UNIT         _BIT_GROUP_
            BIT     0021H.1   0000H.3   UNIT         ?BI?PCC_GLOBALS
            BIT     0021H.4   0000H.1   UNIT         ?BI?_PCC_TIMER_1_WAIT?PCC_SERVICE_ROUTINES
            BIT     0021H.5   0000H.1   UNIT         ?BI?PCC_UART_DRIVER
            BIT     0021H.6   0000H.1   UNIT         ?BI?LOG?LOG
                    0021H.7   0000H.1                *** GAP ***
            DATA    0022H     002CH     UNIT         _DATA_GROUP_
            DATA    004EH     0008H     UNIT         ?DT?_FLOOR?FLOOR
            DATA    0056H     0004H     UNIT         ?DT?_PCC_TIMER_1_WAIT?PCC_SERVICE_ROUTINES
            DATA    005AH     0004H     UNIT         ?DT?LOG?LOG
            DATA    005EH     0001H     UNIT         ?DT?PCC_GLOBALS
            DATA    005FH     0001H     UNIT         ?DT?_CMD_PARSER_CALC_TX_GAINS?PCC_CMD_PARSER
            IDATA   0060H     0049H     UNIT         _IDATA_GROUP_
            IDATA   00A9H     0011H     UNIT         ?ID?_CMD_PARSER_CALC_TX_GAINS?PCC_CMD_PARSER
            IDATA   00BAH     0004H     UNIT         ?ID?MPC_PCC_IF_DRIVER
            IDATA   00BEH     0002H     UNIT         ?ID?UART_COM_GETCHAR?PCC_UART_DRIVER
            IDATA   00C0H     0002H     UNIT         ?ID?UART_GET_RBUFLEN?PCC_UART_DRIVER
            IDATA   00C2H     0001H     UNIT         ?ID?_PCC_TIMER_1_WAIT?PCC_SERVICE_ROUTINES
            IDATA   00C3H     0001H     UNIT         ?STACK
It is not clear to me why after _IDATA_GROUP_ only few functions will be reported as IDATA memory consumers, while many other functions will not report any idata consuming at all (and their local automatic variables are probably included in the _IDATA_GROUP_ general section). I would also like to know if and how I can get a detailed description for the usage of the _IDATA_GROUP_ (which variables from which functions are included in that space). This information will hopefully help me to optimize the code to consume less memory.

Thanks,
Amit Alon.

Parents
  • some more info...
    I have found under the attached map file that when creating a function and never using it, the idata RAM usage is groing bigger, and when i start to call the function it disapears from the section of the map file that is below the _IDATA_GROUP_, and the idata memory utilization is smaller (which is good). Can you please explain that ?

    Can you explain how can I make the UART_COM_GETCHAR and UART_GET_RBUFLEN function disapear ? the library function printf should call function _getkey, which I have overwritten to call another function named UART_com_getchar, which is supposed to call UART_get_rbuflen. it seems that even thogh the UART function operates fine, the compiler can't see that these functions are being called from somewhere, and thus don't perform any idata memory optimization.

Reply
  • some more info...
    I have found under the attached map file that when creating a function and never using it, the idata RAM usage is groing bigger, and when i start to call the function it disapears from the section of the map file that is below the _IDATA_GROUP_, and the idata memory utilization is smaller (which is good). Can you please explain that ?

    Can you explain how can I make the UART_COM_GETCHAR and UART_GET_RBUFLEN function disapear ? the library function printf should call function _getkey, which I have overwritten to call another function named UART_com_getchar, which is supposed to call UART_get_rbuflen. it seems that even thogh the UART function operates fine, the compiler can't see that these functions are being called from somewhere, and thus don't perform any idata memory optimization.

Children
  • when you have Unused functions, you get typically WARNING 16 messages.

    This is documented in the user's guide:
    http://www.keil.com/support/man/docs/lx51/lx51_l16.htm

    Reinhard

  • "Can you explain how can I make the UART_COM_GETCHAR and UART_GET_RBUFLEN function disapear ? the library function printf should call function _getkey, which I have overwritten to call another function named UART_com_getchar, which is supposed to call UART_get_rbuflen"

    Why not just put a breakpoint in _getkey, and see what actually happens?

    I trust that your random capitalisation is just a feature of your typing here, and not really in your code...

    There is an example in the downloads section of interfacing printf to custom (interrupt-driven) serial IO routines - you could try starting from there?

  • Reinhard / Neil,

    (*) My UART code is based on the example that is in your site.

    (*) I have found the reason for the fact that UART_COM_GETCHAR and UART_GET_RBUFLEN where left in the MAP file. This is beacuse they are realy not called from anywhere, since my application used printf and didn't use getch() function. after starting to use getch() they where vanished from the map file.

    (*) The use of "random" capital letters is, as you thought, simply due to coping the variable name from the linker's report. they are all upercase there, not like in the real code.


    These questions are still left unanswered:

    1) I would like to get explanation about the way that the compiler analyze the code and choose which variables can be overlaid, in order to write more efficient code that will consume as less idata memory as possible, and leave as much memory as possible for the stack.

    2) Will the compiler cross files in this kind of optimization ?

    3) I would like to know if and how I can get a detailed description for the usage of the _IDATA_GROUP_ reported in the map file (which variables from which functions are included in that space). This information will hopefully help me to optimize the code to consume less memory.

    additionally can you answer these 2 questions as well ?

    4) If you have any other tips or methodes to get better code that uses less internal RAM, it will help.

    5) In case that I choose compact or large model, should I change manually the DPP (memory page selector) to point at the external RAM before calling any function, in order to assure correct parameters passing into the function, or will the compiler automatically do it for me ?

    Thanks alot,
    Amit A.

  • The use of "random" capital letters is, as you thought, simply due to coping the variable name from the linker's report.
    Always
    use cut-and-paste to ensure that what the forum work on is the real McCoy.

    a)I would like to get explanation about the way that the compiler analyze the code and choose which variables can be overlaid, b)in order to write more efficient code that will consume as less idata memory as possible, and leave as much memory as possible for the stack.

    a) do s search on "call tree"

    b) make as much as possible a call from main(). an example
    main a()
    a b()
    b c()
    c d()
    d e()
    may use a number of data slots

    main a()
    if flag c()

    a b()
    b set flag

    c d()
    d e()
    will probably use far less

    also
    main a(Samevar)
    a b(Samevar)
    b c(Samevar)
    c d(Samevar)
    is wasteful compared to

    var
    main a()
    a b()
    b c()
    c d()

    will the compiler cross files in this kind of optimization ?
    if I understand your question: no, but the linker will. All variable overlaying is doone by the linker.

    Erik

  • YES, I know, the above is not what purists label "correct C" but it is a heck of a lot better than not having enough memory - or - even worse, killing throughput by starting to use xdata for popular variables.

    Most of the rules for "good C" have been created for resource monsters which the '51 definitely is not. Of course if you suffer from the "mini PC syndrome" the above will make you cringe, but if so, get cured and your '51 projects will smile.

    Erik

  • "a) do s search on 'call tree'"

    and search on "Overlay" (and "Overlaying")

    Also study the Application Note & knowledgebase articles about Function Pointers - they discuss overlaying because of its major implications for Function Pointers.