Hi Steven,
What are the main factors in estimating the minimum RAM quantum needed by a component? (Excluding for this discussion any dynamic allocation an application might perform.)
the RAM demand of a component is the sum of the following parts:
1. Session quotas spent for the fundamental services (PD, CPU, LOG) at core, 2. Copy of the DATA section of the dynamic linker (ld.lib.so), 3. Allocation of the BSS section of the dynamic linker, 4. Copy of the DATA section of the executable, 5. Allocation of the BSS section of the executable, 6. Meta data allocated by the parent(s) of the component like init, 7. Dynamic allocations during the component's initialization (by the dynamic linker and potentially the C++ runtime).
Remarks for further investigation:
(1) on Sculpt, you can reveal the session quotas for all components of the runtime subsystem by adding a 'requested="yes"' attribute the <report> node of /config/managed/runtime. The sessions are then listed in /report/runtime/state. The most prominent consumer of RAM quota is the PD session, which accounts for component- specific kernel data structures (page tables, page directory) and core's representation of the protection domain.
(2) use 'readelf -l build/x86_64/debug/ld-nova.lib.so' to print the segment sizes. The first (read-only) segment is mapped directly from the ELF binary (no additional RAM needed). The second (RW) contains the DATA and BSS segments. To determine the contributors to the segment sizes, you can take a look at the symbols via 'nm'. E.g., 'nm --format=posix build/x86_64/debug/ld-nova.lib.so' prints the size of each symbol as last element of the output.
The static RAM demand of the dynamic linker varies from kernel to kernel. E.g., on seL4 there is a quite large statically allocated array for holding the meta data for the component's capability space.
(6) for init, the local meta data per component is accounted at
https://github.com/genodelabs/genode/blob/master/repos/os/src/init/main.cc#L...
The Genode Foundations book (18.05) suggests that if no quantum is specified, "init has a reasonable default of 160K (on 32 bit)".
This statement refers to the RAM quota init preserves for itself, not the quota assigned to child components. There is no default RAM quota for children.
Experimentally, it seems like even the most modest components need more. For example the client side of the hello_tutorial, essentially 5 source lines and a 20K stripped ELF binary, seems to need about 500K on a 32-bit x86 system.
At quantum="480K" for hello_client, one sees: Warning: PD (init -> hello_client) RAM limit (used=380K, limit=394587) exceeded during transfer_quota(6K) (and the test hangs.)
At 425K, the result is: [init] child "hello_client" requests resources: ram_quota=69632 page fault, pd='init -> hello_client' thread='hello_client' cpu=0 ip=0xa2adc address=0xa00fde50 stack pointer=0x0 qualifiers=0x6 irUWp reason=1
At 300K, we see: [init] Error: allocation of read-write segment failed [init] Error: hello_client: out of RAM during ELF loading
Is there a way to tweak component compilation/linking parameters to minimize physical RAM required?
The most straight-forward tweak would be to enable the size optimization of the compiler by adding the following line to our <build>/etc/tools.conf file:
CC_OLEVEL += -Os
Some time ago, I conducted a series of experiments to find the lower bound of physical memory needed to run a simple Genode scenario. I picked the hello-client-server scenario as example, which comprises core, init, the hello client, and the hello server. You can find the tweaks at the following topic branch:
https://github.com/nfeske/genode/commits/size_test
With those tweaks I was able to run the scenario on the hw_pbxa9 base platform on Qemu with 3200 KiB of memory. I haven't repeated the experiment ever since. So I'm not sure how applicable the tweaks are on the current version of Genode. But maybe they can serve you as a starting point?
Cheers Norman