blob: 272aa21c55fa4f7cff3f7660bdb7574cb3e4d0f1 [file] [log] [blame]
Denis Vlasenko75605782007-03-14 00:07:51 +00001 Keeping data small
2
3When many applets are compiled into busybox, all rw data and
4bss for each applet are concatenated. Including those from libc,
5if static bbox is built. When bbox is started, _all_ this data
6is allocated, not just that one part for selected applet.
7
8What "allocated" exactly means, depends on arch.
9On nommu it's probably bites the most, actually using real
10RAM for rwdata and bss. On i386, bss is lazily allocated
11by COWed zero pages. Not sure about rwdata - also COW?
12
13Small experiment measures "parasitic" bbox memory consumption.
14Here we start 1000 "busybox sleep 10" in parallel.
15bbox binary is practically allyesconfig static one,
16built against uclibc:
17
18bash-3.2# nmeter '%t %c %b %m %p %[pn]'
Denis Vlasenko9616aff2007-03-14 11:50:34 +00001923:17:28 .......... 0 0 168M 0 147
2023:17:29 .......... 0 0 168M 0 147
2123:17:30 U......... 0 0 168M 1 147
2223:17:31 SU........ 0 188k 181M 244 391
2323:17:32 SSSSUUU... 0 0 223M 757 1147
2423:17:33 UUU....... 0 0 223M 0 1147
2523:17:34 U......... 0 0 223M 1 1147
2623:17:35 .......... 0 0 223M 0 1147
2723:17:36 .......... 0 0 223M 0 1147
2823:17:37 S......... 0 0 223M 0 1147
2923:17:38 .......... 0 0 223M 1 1147
3023:17:39 .......... 0 0 223M 0 1147
3123:17:40 .......... 0 0 223M 0 1147
3223:17:41 .......... 0 0 210M 0 906
3323:17:42 .......... 0 0 168M 1 147
3423:17:43 .......... 0 0 168M 0 147
Denis Vlasenko75605782007-03-14 00:07:51 +000035
36This requires 55M of memory. Thus 1 trivial busybox applet
37takes 55k of userspace memory (nmeter doesn't account for kernel-side
38allocations). Definitely can be improved.
39
40Thus we should avoid large global data in our applets,
41and should minimize usage of libc functions which implicitly use
42such structures in libc.
43
44 Example 1
45
46One example how to reduce global data usage is in
47archival/libunarchive/decompress_unzip.c:
48
49/* This is somewhat complex-looking arrangement, but it allows
50 * to place decompressor state either in bss or in
51 * malloc'ed space simply by changing #defines below.
52 * Sizes on i386:
53 * text data bss dec hex
54 * 5256 0 108 5364 14f4 - bss
55 * 4915 0 0 4915 1333 - malloc
56 */
57#define STATE_IN_BSS 0
58#define STATE_IN_MALLOC 1
59
60This example completely eliminates globals in that module.
61Required memory is allocated in inflate_gunzip() [its main module]
62and then passed down to all subroutines which need to access globals
63as a parameter.
64
65 Example 2
66
67In case you don't want to pass this additional parameter everywhere,
68take a look at archival/gzip.c. Here all global data is replaced by
69singe global pointer (ptr_to_globals) to allocated storage.
70
71In order to not duplicate ptr_to_globals in every applet, you can
72reuse single common one. It is defined in libbb/messages.c
73as void *ptr_to_globals, but is NOT declared in libbb.h.
74You first define a struct:
75
76struct my_globals { int a; char buf[1000]; };
77
78and then declare that ptr_to_globals is a pointer to it:
79
80extern struct my_globals *ptr_to_globals;
81#define G (*ptr_to_globals)
82
83Linker magic enures that these two merge into single pointer object.
84Now initialize it in <applet>_main():
85
86 ptr_to_globals = xzalloc(sizeof(G));
87
88and you can reference "globals" by G.a, G.buf and so on, in any function.