TIPS: Space optimisation
CardboardGuru
Posts: 443
I'm currently doing some work on Donkey Kong in order to squeeze everything in to 32K. As most people are going to have to do some space optimisation with their programs at some time, I though it was worth starting a list of tips that everyone could contribute to as a resource.
1) Don't do it until you have to. Who knows, you might never need to. By optimising for space, you might make your code slower. And until your program has formed it's final shape, it may not be obvious where the biggest potential space savings are.
2) If you spot a good optimisation before you actually need the space, then rather than do it, add a comment and then come back to it when you do need the space.
3) Copy the spin file(s) before you start. In fact it's a good time to create a new version number. It's very easy to introduce bugs as you refactor your code or data. You will be thankful to have a previous version to refer back to.
4) Test often. You want to find bugs as soon as they appear.
5) Have a target in mind. You want to add in a sound driver, or a new level. When you do so, the compiler tells you you're short by X longs. Write is down, comment out the new added code. Then do space optimisation until you've saved that much space. Then stop. You don't have to optimise it all in one go.
6) Keep a log. Before you do each section of optimisation bring up Object Info with Ctrl-F8 and note down the Stack/Free number. And then compare after you've done the optimisation. It's often surprising that the optimisations that you think are going to be good are not so good and vice versa. Occasionally you'll actually end up using more memory, so you'll need to revert. The only way to learn is to look at the numbers after every step.
7) Let Propeller Tool guide you. After you've compiled, but before you make any more changes, the Prop Tool will display in the status bar the length (in bytes) of any individual functions or DAT sections you have. Switch to Summary view and you can skip through each section to see where your memory went. Work on the largest function or data section first.
8) In Spin, only use globals when you need them. Prefer locals. This is contrary to the general advice on page 451 of the Hydra book (which is true for C and most other languages). It turns out that Spin uses more byte code to access globals than locals. In a long function in Donkey Kong I had an index long and a pointer which were both locals. I changed them to globals so that I could access them in called functions without passing them as parameters, and the the memory usage went up by around 100 longs! Some investigation into which is faster would be in order however.
9) If it's a tile based game, consider compressing the tile maps for a big easy gain. If there is a lot of repetition you could store them as run length encoded, or draw them with code. For DK I ended up with a tiny byte code interpreter for drawing commands. Level maps which were originally 1792 bytes each ended up as 109, 127, 88 and 139 bytes long respectively, with the byte code interpreter/drawer only 272 bytes long.
10) For arrays, consider if they could be word or bytes rather than longs.
11) A lot of your functions are likely to be state machines. Largely a long case statement. Look for states where functionality is very similar and consider merging states or refactoring them into a function with the differences passed in as arguments. For example I have a lot of states where the only difference is whether movement is left or right on the screen. I could change to having a common state plus a direction variable, or use sub functions to which the direction is passed as an argument.
Post Edited (CardboardGuru) : 5/24/2007 4:27:24 PM GMT
1) Don't do it until you have to. Who knows, you might never need to. By optimising for space, you might make your code slower. And until your program has formed it's final shape, it may not be obvious where the biggest potential space savings are.
2) If you spot a good optimisation before you actually need the space, then rather than do it, add a comment and then come back to it when you do need the space.
3) Copy the spin file(s) before you start. In fact it's a good time to create a new version number. It's very easy to introduce bugs as you refactor your code or data. You will be thankful to have a previous version to refer back to.
4) Test often. You want to find bugs as soon as they appear.
5) Have a target in mind. You want to add in a sound driver, or a new level. When you do so, the compiler tells you you're short by X longs. Write is down, comment out the new added code. Then do space optimisation until you've saved that much space. Then stop. You don't have to optimise it all in one go.
6) Keep a log. Before you do each section of optimisation bring up Object Info with Ctrl-F8 and note down the Stack/Free number. And then compare after you've done the optimisation. It's often surprising that the optimisations that you think are going to be good are not so good and vice versa. Occasionally you'll actually end up using more memory, so you'll need to revert. The only way to learn is to look at the numbers after every step.
7) Let Propeller Tool guide you. After you've compiled, but before you make any more changes, the Prop Tool will display in the status bar the length (in bytes) of any individual functions or DAT sections you have. Switch to Summary view and you can skip through each section to see where your memory went. Work on the largest function or data section first.
8) In Spin, only use globals when you need them. Prefer locals. This is contrary to the general advice on page 451 of the Hydra book (which is true for C and most other languages). It turns out that Spin uses more byte code to access globals than locals. In a long function in Donkey Kong I had an index long and a pointer which were both locals. I changed them to globals so that I could access them in called functions without passing them as parameters, and the the memory usage went up by around 100 longs! Some investigation into which is faster would be in order however.
9) If it's a tile based game, consider compressing the tile maps for a big easy gain. If there is a lot of repetition you could store them as run length encoded, or draw them with code. For DK I ended up with a tiny byte code interpreter for drawing commands. Level maps which were originally 1792 bytes each ended up as 109, 127, 88 and 139 bytes long respectively, with the byte code interpreter/drawer only 272 bytes long.
10) For arrays, consider if they could be word or bytes rather than longs.
11) A lot of your functions are likely to be state machines. Largely a long case statement. Look for states where functionality is very similar and consider merging states or refactoring them into a function with the differences passed in as arguments. For example I have a lot of states where the only difference is whether movement is left or right on the screen. I could change to having a common state plus a direction variable, or use sub functions to which the direction is passed as an argument.
Post Edited (CardboardGuru) : 5/24/2007 4:27:24 PM GMT
Comments
My main motivation in proposing the SCuM project (http://forums.parallax.com/showthread.php?p=651668) was to give developers a way to provide this kind of "take only what you need" capability in their objects via C-like precompiler directives (#IF, #ENDIF, #DEFINE).
Good one. But I guess there's a problem with doing this with the drivers on the Hydra Book CD. You're not supposed to distribute those, so the users will end up using the full version surely?
Definitely one to do for any Parallax or public domain or GPLed drivers though.