[solved] Garbage Collection, again
SRLM
Posts: 5,045
Well, I'm starting to get near the limit of available memory, and I would like to see if we can get automatic garbage collection back.
History
http://forums.parallax.com/showthread.php/144139-PropGCC-Problems-garbage-collecting-functions
Motivation
GCC does not provide automatic garbage collection. That is unfortunate, due to the Propeller's limited memory size. It would be nice if garbage collection was done automatically at compile time for the unused functions and variables.
Changes
In the newest version of PropGCC (on the p2test branch, v0_3_5_1920+) there is the new kerext feature. While this may be useful for improving kernel performance, it breaks the older half working style of garbage collection. This is because it uses a __load_start_* type identifier, which I wasn't able to get working before.
Current Work
I've attached a simple program and associated Makefile and main.ld script. I tried various KEEP directives in the main.ld script, and I'm able to prevent the section from being garbage collected. But, in the end, it always comes down to one error:
I have no idea where to look. Any suggestions would be welcome, and a solution would be wonderful.
On a slightly related note, I found that on line 191 of propgcc/gcc/gcc/config/propeller/kernel.ext it has "long", but not ".long" like the very similar looking section on line 87. Since the linker is not complaining about __load_start_math_kerext, I thought that single period might be it. So, I recompiled PropGCC with that change (I presume, it's my first time with a change) and the problem persists.
History
http://forums.parallax.com/showthread.php/144139-PropGCC-Problems-garbage-collecting-functions
Motivation
GCC does not provide automatic garbage collection. That is unfortunate, due to the Propeller's limited memory size. It would be nice if garbage collection was done automatically at compile time for the unused functions and variables.
Changes
In the newest version of PropGCC (on the p2test branch, v0_3_5_1920+) there is the new kerext feature. While this may be useful for improving kernel performance, it breaks the older half working style of garbage collection. This is because it uses a __load_start_* type identifier, which I wasn't able to get working before.
Current Work
I've attached a simple program and associated Makefile and main.ld script. I tried various KEEP directives in the main.ld script, and I'm able to prevent the section from being garbage collected. But, in the end, it always comes down to one error:
/opt/parallax/lib/gcc/propeller-elf/4.6.1/_crtend.o /opt/parallax/lib/gcc/propeller-elf/4.6.1/_crt0.o: In function `__mem_kernel_ptr': (.kernel+0x4f8): undefined reference to `__load_start_memory_kerext' collect2: ld returned 1 exit status make: *** [Debug] Error 1
I have no idea where to look. Any suggestions would be welcome, and a solution would be wonderful.
On a slightly related note, I found that on line 191 of propgcc/gcc/gcc/config/propeller/kernel.ext it has "long", but not ".long" like the very similar looking section on line 87. Since the linker is not complaining about __load_start_math_kerext, I thought that single period might be it. So, I recompiled PropGCC with that change (I presume, it's my first time with a change) and the problem persists.
Comments
We'll remove it from the sources, but for the moment you can get around the error by either (1) defining __load_start_memory_kerext to 0 somewhere, or (2) providing a reference to some function in the .memory.kerext section, like __Memcpy. Option (1) will save you around 156 bytes of memory, so it's probably the better one.
Thanks for the bug report,
Eric
I've been trying things on and off for over four months now, trying to get this to work. Your post provided the inspiration to solve the problem.
Value of Garbage collection
For the fairly large program that I'm developing, I'm able to get the following code size reduction for "free" using garbage collection: 2KB extra space is pretty generous. With the toggle code attached, the savings are: An incredible savings of almost 8KB, more than half the program.
How To
The trick was to provide a reference to the assembly code so that it would not be pruned by the linker. I did this by adding the following to the cog GAS assembly driver:
Then, somewhere in the main, I added:
Now, the compiler will not optimize the reference away, and the linker won't prune assembly drivers.
I've attached a version of the GAS toggle demo that has these features, along with the makefile and main.ld linker scirpt.
Implementation details
I didn't have to add anything specific to the linker script for the .cogtoggle section code. The only modifications that I made from the default linker script was to add the KEEP directive around some of the more important looking sections. It would be nice if the default propgcc linker script were updated to include these keep directives, since it will work for all PropGCC implementations.
GCC does not garbage collect by default. To do that, you have to add some linker options: The --script option specifies a linker script to use.
The --gc-sections instructs the linker to garbage collect.
The --print-gc-sections prints what was removed.
The --verbose outputs a bunch of information, including the linker script used.
I tried the following code to make a reference instead of the inline assembly, but it got optimized out with -Os.
It would be nice if the reference generation could be done automatically in one of the startup sections (.r0 - .r9?), but I don't know enough yet to provide suggestions on how to do this.
I'm using a recent build:
Nice work!! Thanks for sticking with this!
I have tried it with CMM and LMM, but not any other memory models ( I don't have a board with external memory). Any suggestions on what to add for those would be welcome as well.
If this diff meets with everybody's approval, I'd like to commit it to the repository myself.
Yes I can. Once I do, I'll go ahead and add a tutorial on the Google Sites area. Which brings up another question: where is the preferred area for documentation: the wiki, the PropGCC Google Sites pages, ...?
For now use: https://sites.google.com/site/propellergcc/
It's easier to make nice pages there.
Both that site and propgcc wiki pages will be consolidated into another site soon. The old material will be removed.
If so I look forward to checking it out. For example TinyJS is a 60KByte program pulling in 550KBytes of C++ library code. I'm sure TinyJS is not using most of that.
--gc-sections removes sections that do not have a reference to them. To remove individual functions you must compile with -ffunction-sections. You can do the same for variables with the -fdata-sections flag. For many library functions this is not applicable, because each function is compiled into a separate .o file (and the compiler would not pull it in). It does come in handy, however, when multiple functions are put into the same file.
The following cuts take out 3kB of code size, down to 12.5kB:
As an interesting aside, you could modify the default linker script to change the size of hub memory, and compile very large programs (MB of memory, anyone? ). Of course it won't run...
I've been using the changes for the last few weeks, and everything seems to be working fine. I've used it on small and large projects, LMM and CMM, with and without standard library, and with external .S files.
I should note one thing: I've only tried it with propeller-elf-g++ (using C++), not propeller-elf-gcc (using C).
@SRLM: Thank you for doing all this!
@ersmith, David Betz, jazzed: Thank you for following up on this feature!