elks icon indicating copy to clipboard operation
elks copied to clipboard

Researching RAM usage reduction

Open asiekierka opened this issue 8 months ago • 4 comments

I've been doing some analysis on sash to figure out any bottlenecks on the user, rather than kernel, side of memory usage. I apologize for the barrage of questions that is to follow:

  • stdin, stdout and stderr user-side buffers are 1 KB each by default; that's 3 KB of data segment use for pretty much any non-trivial program. Do they need to be this large?
  • In sash:cmd_ed.c (as well as misc_utils:ed.c), the maximum search string size is 1 KB; this value is allocated as a constant in the data segment, which is particularly annoying in sash, which forks to load processes. Perhaps, for sash, one could combine it with cmd_tar.c's dblock (512 bytes) in an union, as the two values won't be used at the same time.
  • ... Given that a very similar version of ed is packages as misc_utils:ed.c, is there a reason to compile ed into sash at all? It does save a few (~6-10?) kilobytes of RAM when ed is used, at the cost of losing ~6 KiB of RAM when ed is not used. It's probably the most noticeable such case, as most other programs are indeed significantly lighter in their sash implementations.

asiekierka avatar Apr 21 '25 04:04 asiekierka

You can source some ideas from here: https://github.com/ghaerr/elks/wiki/Increase-available-memory

toncho11 avatar Apr 22 '25 05:04 toncho11

Oops, I didn't see this issue. I'll respond tomorrow.

ghaerr avatar Apr 22 '25 05:04 ghaerr

user-side buffers are 1 KB each by default; that's 3 KB of data segment use for pretty much any non-trivial program. Do they need to be this large?

It's a good question. I've already got mods in some programs to reduce the "standard" size of 1K, for instance, see elkscmd/sys_utils/init.c.

While we've worked hard to reduce the size of programs executable image size, not as much effort has been made to reduce the size of the data segment, so this needs further looking into, for sure. As it now stands, I've tried to keep the buffer sizes, as well as the read/writes by programs, equal to the 1K MINIX block size. But the internal kernel pipe buffer is now an astoundingly small 80 bytes. This was done as a quicker hack to reduce the size of kernel data, but doesn't seem to slow down piped commands that much. Its questionable how fast piped commands need to be anyways at the expense of our increasingly limited kernel data segment size.

The stderr buffer is probably way too large at 1K and could be moved to 80. Perhaps we should have a define to build the C library stdio at a smaller default size, then test to see how much slower things get. We should define some parameters as to what we really want to test though, whether its data segment size, image size, speed of pipes, speed of disk I/O, etc.

Perhaps, for sash, one could combine it with cmd_tar.c's dblock (512 bytes) in an union, as the two values won't be used at the same time.

Probably a good idea, if you're trying to get sash's size to be much smaller.

is there a reason to compile ed into sash at all?

The original reason was to allow sash to be a true stand alone shell for data recovery; but I think that's not really needed - we've got other tools for that and that's likely overkill for non-distribution ELKS always. I'm ok with removing ed and/other features from sash in an effort for ROM and tight RAM based systems to have a shell that allows more programs to run. Take a pass at it - it's quite easy to remove and/or add back, given the config.h mechanism already in place.

I've got to run off for a bit, but look forward to more discussion on this important topic!

ghaerr avatar Apr 22 '25 16:04 ghaerr

Perhaps we should have a define to build the C library stdio at a smaller default size

Compiling the C library specially for different architectures is kind of asking for trouble, but for systems that are very tight on RAM, various kernel and C library buffer and other limits could be brought down considerably, if sticking to standard definitions: kernel include/linuxmt/limits.h or C library libc/include/limits.h could hold smaller limits for ROM systems.

In particular, BUFSIZ (which is currently defined in stdio.h) and PATH_MAX could be decreased substantially, which might help. I've already made a first pass modifying all applications to use limits.h for PATH_MAX; another pass could be made, especially for applications that need to be trimmed down on memory-tight systems.

Note however, that including config.h in a common C library header file greatly increases time spent by programmers waiting for the system to be rebuilt, especially when multiple architectures need to be tested. The Github CI is already long, being run on every push for fast programmers. I spent a lot of time cleaning up the C library includes so that it doesn't have these issues anymore. However, given that we're wasting RAM in many cases and don't yet actually have a way to drastically decrease RAM usage for memory-tight systems, we need a solution, and this could work if done carefully.

Other potential solutions are detailed below, which likely vary on a per-application basis.

Ways to decrease data (and code) segment size in both applications and kernel:

  • Link with elkscmd/lib/tiny_vfprintf.c. Many applications already do this, which replaces the full-blown printf with a much smaller version, with limitations on format string processing. Tiny printf also replaces the stdout and stderr stream buffer definitions with 80 bytes each, saving 1888 bytes, along with less code. Certain applications could be linked with a file that only changes the stdio file stream buffer sizes, rather than printf, to decrease RAM usage. This tends to only matter if the applications are always resident, and these enhancements have already been made to init, getty, login, and some others.
  • Work on sash to become a very tiny shell, rather than a recovery shell. This could be combined with a better-thought-out ROM distribution that doesn't include utilities that are included in sash, or vice-versa.
  • Work on a vfork, or Windows spawn-style exec even, that uses much less memory to start another process. ELKS already has a vfork, but I've temporarily removed it as it resulted in system instability which I haven't fully traced to find the issue.
  • Tuning the system by decreasing the max size of kernel resources: tasks, files, L1 buffer cache, L2 buffers, etc. This was mentioned above by @toncho11 in "You can source some ideas from here:". The kernel heap size can usually be decreased quite a bit based on the kinds of programs present in ROMFS. Task structures in particular are very large at 1K+ each, along with L1 and L2 buffers.
  • Decrease the size of serial input buffers: currently 1K default for use with SLIP networking. These are defined in include/linuxmt/ntty.h.
  • Decrease the number of consoles, console pages, PTYs, etc.

ghaerr avatar Apr 23 '25 02:04 ghaerr