blob: fcd8df4a93877ed1c9d0dde4d535bd4964f741bd [file] [log] [blame]
Denis Vlasenko4efeaee2007-03-15 19:52:42 +00001 Keeping data small
Denis Vlasenko75605782007-03-14 00:07:51 +00002
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
Denis Vlasenko4efeaee2007-03-15 19:52:42 +000013In order to keep bbox NOMMU and small-mem systems friendly
14we should avoid large global data in our applets, and should
15minimize usage of libc functions which implicitly use
16such structures in libc.
17
Denis Vlasenko75605782007-03-14 00:07:51 +000018Small experiment measures "parasitic" bbox memory consumption.
19Here we start 1000 "busybox sleep 10" in parallel.
20bbox binary is practically allyesconfig static one,
21built against uclibc:
22
23bash-3.2# nmeter '%t %c %b %m %p %[pn]'
Denis Vlasenko9616aff2007-03-14 11:50:34 +00002423:17:28 .......... 0 0 168M 0 147
2523:17:29 .......... 0 0 168M 0 147
2623:17:30 U......... 0 0 168M 1 147
2723:17:31 SU........ 0 188k 181M 244 391
2823:17:32 SSSSUUU... 0 0 223M 757 1147
2923:17:33 UUU....... 0 0 223M 0 1147
3023:17:34 U......... 0 0 223M 1 1147
3123:17:35 .......... 0 0 223M 0 1147
3223:17:36 .......... 0 0 223M 0 1147
3323:17:37 S......... 0 0 223M 0 1147
3423:17:38 .......... 0 0 223M 1 1147
3523:17:39 .......... 0 0 223M 0 1147
3623:17:40 .......... 0 0 223M 0 1147
3723:17:41 .......... 0 0 210M 0 906
3823:17:42 .......... 0 0 168M 1 147
3923:17:43 .......... 0 0 168M 0 147
Denis Vlasenko75605782007-03-14 00:07:51 +000040
41This requires 55M of memory. Thus 1 trivial busybox applet
Denis Vlasenko4efeaee2007-03-15 19:52:42 +000042takes 55k of memory.
Denis Vlasenko75605782007-03-14 00:07:51 +000043
Denis Vlasenko75605782007-03-14 00:07:51 +000044
Denis Vlasenko4efeaee2007-03-15 19:52:42 +000045 Example 1
Denis Vlasenko75605782007-03-14 00:07:51 +000046
47One example how to reduce global data usage is in
48archival/libunarchive/decompress_unzip.c:
49
50/* This is somewhat complex-looking arrangement, but it allows
51 * to place decompressor state either in bss or in
52 * malloc'ed space simply by changing #defines below.
53 * Sizes on i386:
54 * text data bss dec hex
55 * 5256 0 108 5364 14f4 - bss
56 * 4915 0 0 4915 1333 - malloc
57 */
58#define STATE_IN_BSS 0
59#define STATE_IN_MALLOC 1
60
Denis Vlasenko4efeaee2007-03-15 19:52:42 +000061(see the rest of the file to get the idea)
62
Denis Vlasenko75605782007-03-14 00:07:51 +000063This example completely eliminates globals in that module.
64Required memory is allocated in inflate_gunzip() [its main module]
Denis Vlasenko972288e2007-03-15 00:57:01 +000065and then passed down to all subroutines which need to access 'globals'
Denis Vlasenko75605782007-03-14 00:07:51 +000066as a parameter.
67
Denis Vlasenko4efeaee2007-03-15 19:52:42 +000068
69 Example 2
Denis Vlasenko75605782007-03-14 00:07:51 +000070
71In case you don't want to pass this additional parameter everywhere,
72take a look at archival/gzip.c. Here all global data is replaced by
Denis Vlasenko972288e2007-03-15 00:57:01 +000073single global pointer (ptr_to_globals) to allocated storage.
Denis Vlasenko75605782007-03-14 00:07:51 +000074
75In order to not duplicate ptr_to_globals in every applet, you can
76reuse single common one. It is defined in libbb/messages.c
Denis Vlasenko4efeaee2007-03-15 19:52:42 +000077as struct globals *const ptr_to_globals, but the struct globals is
Denis Vlasenko972288e2007-03-15 00:57:01 +000078NOT defined in libbb.h. You first define your own struct:
Denis Vlasenko75605782007-03-14 00:07:51 +000079
Denis Vlasenko972288e2007-03-15 00:57:01 +000080struct globals { int a; char buf[1000]; };
Denis Vlasenko75605782007-03-14 00:07:51 +000081
82and then declare that ptr_to_globals is a pointer to it:
83
Denis Vlasenko75605782007-03-14 00:07:51 +000084#define G (*ptr_to_globals)
85
Denis Vlasenko4efeaee2007-03-15 19:52:42 +000086ptr_to_globals is declared as constant pointer.
87This helps gcc understand that it won't change, resulting in noticeably
88smaller code. In order to assign it, use PTR_TO_GLOBALS macro:
Denis Vlasenko75605782007-03-14 00:07:51 +000089
Denis Vlasenko4efeaee2007-03-15 19:52:42 +000090 PTR_TO_GLOBALS = xzalloc(sizeof(G));
Denis Vlasenko75605782007-03-14 00:07:51 +000091
Denis Vlasenko4efeaee2007-03-15 19:52:42 +000092Typically it is done in <applet>_main().
Denis Vlasenko972288e2007-03-15 00:57:01 +000093
Denis Vlasenko4efeaee2007-03-15 19:52:42 +000094Now you can reference "globals" by G.a, G.buf and so on, in any function.
95
96
97 bb_common_bufsiz1
98
99There is one big common buffer in bss - bb_common_bufsiz1. It is a much
100earlier mechanism to reduce bss usage. Each applet can use it for
101its needs. Library functions are prohibited from using it.
102
103'G.' trick can be done using bb_common_bufsiz1 instead of malloced buffer:
104
105#define G (*(struct globals*)&bb_common_bufsiz1)
106
107Be careful, though, and use it only if
108sizeof(struct globals) <= sizeof(bb_common_bufsiz1).
109
110
111 Drawbacks
112
113You have to initialize it by hand. xzalloc() can be helpful in clearing
114allocated storage to 0, but anything more must be done by hand.
115
116All global variables are prefixed by 'G.' now. If this makes code
117less readable, use #defines:
118
119#define dev_fd (G.dev_fd)
120#define sector (G.sector)
121
122
123 Word of caution
124
Bernhard Reutner-Fischer486e7ca2007-03-16 11:14:38 +0000125If applet doesn't use much of global data, converting it to use
126one of above methods is not worth the resulting code obfuscation.
127If you have less than ~300 bytes of global data - don't bother.
Denis Vlasenko3d101dd2007-03-19 16:04:11 +0000128
129
130 gcc's data alignment problem
131
132The following attribute added in vi.c:
133
134static int tabstop;
135static struct termios term_orig __attribute__ ((aligned (4)));
136static struct termios term_vi __attribute__ ((aligned (4)));
137
138reduced bss size by 32 bytes, because gcc sometimes aligns structures to
139ridiculously large values. asm output diff for above example:
140
141 tabstop:
142 .zero 4
143 .section .bss.term_orig,"aw",@nobits
144- .align 32
145+ .align 4
146 .type term_orig, @object
147 .size term_orig, 60
148 term_orig:
149 .zero 60
150 .section .bss.term_vi,"aw",@nobits
151- .align 32
152+ .align 4
153 .type term_vi, @object
154 .size term_vi, 60
155
156gcc doesn't seem to have options for altering this behaviour.