CE memory division between "storage" & "program" memory

Somehow I've been involved in a bunch of discussions on this subject lately, so I figured I might as well lay out some of the issues.

Q:   What are the ways to set the way memory splits between storage & program memory?  Or in other words, how do I set the size of the object store?

A:   You have 3 options:  Set the size in OAL code by implementing the pOEMCalcFSPages function.  Set the size in OAL settings by changing the value of FSRAMPERCENT in config.bib.  Set the size at run-time by calling the SetSystemMemoryDivision function.  The CE control panel "system" applet has a slider that users can drag to adjust the size; that just calls SetSystemMemoryDivision.

Q: What is the minimum size for the object store?  If all of my device settings are stored on a persistent file system, so that I don't use the object store at all, can I set the object store to 0?

A: There is no way to completely get rid of the object store, even in the most recent OS version (5.0).  The absolute minimum value you can use is 28KB.  If you're using FSRAMPERCENT, use FSRAMPERCENT=0x00000004 which gives you 32KB.  If you are actually using the object store for some data, I can't really give you a minimum.  (eg. I can't say what the min. size required to boot successfully is.)  I suggest you find it by booting and seeing how much of the object store is consumed, using GetStoreInformation or GetDiskFreeSpace.

Q: What is the maximum size for the object store?

A: 256MB.  But since FSRAMPERCENT can't go that high, you'll have to use pOEMCalcFSPages for that.

Q: What is the minimum size for the program memory?  How do I guarantee that my device can boot?

A:  Again, there isn't any one minimum size I can give you. It varies based on what components you have included in your image, and based on your own code.  What I suggest is that you find out what the minimum number of free pages was, after booting a system that has enough RAM. Use the "mi" command from the target control window, and look for the "minfree pages" value. That is a "low water mark" for the lowest number of free pages that were available at any one time. Subtract that from the total pages to find out the maximum number of pages that were used at any one time. I think the object store pages count in that total, so you should subtract the size of the object store, to get the maximum number of pages that were used for program memory. Then add some space for safety -- say 24 pages. (I just made that number up.) Then use that as your minimum size for program memory. So, that means use this formula:

   (minimum RAM size) = (total pages) - (minfree pages) - (number of object store pages) + (safety margin)

Q: What is the maximum size for the program memory?

A: 512MB, minus the 28KB minimum for the object store. There is a way to extend past 512MB but that is a story for another day.

Q: How does FSRAMPERCENT work? It is confusing.

A: Yes, it is confusing. To help you understand where it is coming from: back in the days when memory was much smaller, OEMs wanted ways to give stair-step functions of memory, so that they could create multiple devices that vary only by the amount of RAM inside them. FSRAMPERCENT says, for each of the first four 2MB chunks of RAM, how many 4KB pages per 1MB should be given to the object store. So you could say, if my device has 2MB of RAM use this much; if it has 4MB use this other amount, etc. pOEMCalcFSPages is a later way to solve the same problem, and is much more flexible. Anyway here are some tips for reading and setting FSRAMPERCENT:

  • To interpret a value like 0x40302010, take each byte separately. Each byte represents the number of 4KB blocks per MB for 2MB. So 0x40 x 4KB = 256KB per MB for 2MB; so the top byte gives 512KB of RAM to the object store, and the remaining 1.5MB to program memory. Likewise 0x30 --> 384KB storage, 1.625MB program; 0x20 --> 256KB storage, 1.75MB program; 0x10 --> 128KB storage, 1.875MB program. Add them together for the total: 1.25MB storage and 6.75MB program. Check that they add to 8MB. Beyond the first 8MB, all the memory is used as program memory (I think). Don't take my word for it. :-)
  • To specify that N bytes of RAM (where 28KB <= N < 2MB) should be given to the object store, round to the nearest 8KB boundary [N], then set the bottom byte of FSRAMPERCENT to ([N] / (4096 * 2)). So for 28K, round up to 32K, divide by 8KB to get FSRAMPERCENT=0x04. To specify amounts between 2MB and 8MB set the bottom bytes to 0xFF, subtracting 2MB for each.
  • To specify that P% of RAM (where 0 <= P <= 100) should be given to the object store, set each byte of FSRAMPERCENT to ((P / 100) * (1MB / 4KB)), or in simplified form (P * 2.56). So for example to use 12.5% of RAM for the object store, use (12.5 * 2.56) = 32 = 0x20. So the 4-byte value of FSRAMPERCENT would be 0x20202020. To use 33.3% of RAM, set FSRAMPERCENT to 0x55555555.

Q: When I change the division dynamically using SetSystemMemoryDivision or by moving the control panel slider, does that value persist?

A: If your device always warm-boots, the object store will always be there so its size will not change on reboot. If your device always cold-boots, then the object store is recreated on every boot. The division is NOT saved anywhere so it will not persist across cold boots. Every time you cold boot you get whatever size is specified by FSRAMPERCENT / pOEMCalcFSPages. (The other variant of this question is: Why doesn't the registry value that stores the memory division seem to persist when the rest of my registry does? The answer is that there is no such registry value.)

Q: Does all of this apply to PocketPC / MS Smartphone?

A: Well, yes, except that PocketPC (and maybe SP, I'm not sure) has a background thread that dynamically moves the memory division in the background, so that you always have some storage memory and always have some program memory. So any changes you make on PPC/SP will quickly go away when that thread kicks in.