diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-03-14 00:07:51 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-03-14 00:07:51 +0000 |
commit | 75605788ff6be5a766a7e41da583d5e8f47d9ac4 (patch) | |
tree | 36853bddc7322d7a30c3dab2f064b8da7efe481e | |
parent | 07766bb0e7adcefa5dd5a373986176a5cd42ed23 (diff) | |
download | busybox-w32-75605788ff6be5a766a7e41da583d5e8f47d9ac4.tar.gz busybox-w32-75605788ff6be5a766a7e41da583d5e8f47d9ac4.tar.bz2 busybox-w32-75605788ff6be5a766a7e41da583d5e8f47d9ac4.zip |
gzip: use common bbunzip infrastructure - ~700 bytes code less
-rw-r--r-- | archival/Kbuild | 2 | ||||
-rw-r--r-- | archival/bbunzip.c | 23 | ||||
-rw-r--r-- | archival/gzip.c | 171 | ||||
-rw-r--r-- | docs/keep_data_small.txt | 88 |
4 files changed, 185 insertions, 99 deletions
diff --git a/archival/Kbuild b/archival/Kbuild index 011feee5f..07b442f15 100644 --- a/archival/Kbuild +++ b/archival/Kbuild | |||
@@ -14,7 +14,7 @@ lib-$(CONFIG_CPIO) += cpio.o | |||
14 | lib-$(CONFIG_DPKG) += dpkg.o | 14 | lib-$(CONFIG_DPKG) += dpkg.o |
15 | lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o | 15 | lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o |
16 | lib-$(CONFIG_GUNZIP) += bbunzip.o | 16 | lib-$(CONFIG_GUNZIP) += bbunzip.o |
17 | lib-$(CONFIG_GZIP) += gzip.o | 17 | lib-$(CONFIG_GZIP) += gzip.o bbunzip.o |
18 | lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o | 18 | lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o |
19 | lib-$(CONFIG_RPM) += rpm.o | 19 | lib-$(CONFIG_RPM) += rpm.o |
20 | lib-$(CONFIG_TAR) += tar.o | 20 | lib-$(CONFIG_TAR) += tar.o |
diff --git a/archival/bbunzip.c b/archival/bbunzip.c index f7c861256..e16e6b083 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c | |||
@@ -9,12 +9,12 @@ | |||
9 | #include "unarchive.h" | 9 | #include "unarchive.h" |
10 | 10 | ||
11 | enum { | 11 | enum { |
12 | OPT_STDOUT = 1, | 12 | OPT_STDOUT = 0x1, |
13 | OPT_FORCE = 2, | 13 | OPT_FORCE = 0x2, |
14 | /* gunzip only: */ | 14 | /* gunzip only: */ |
15 | OPT_TEST = 4, | 15 | OPT_VERBOSE = 0x4, |
16 | OPT_DECOMPRESS = 8, | 16 | OPT_DECOMPRESS = 0x8, |
17 | OPT_VERBOSE = 0x10, | 17 | OPT_TEST = 0x10, |
18 | }; | 18 | }; |
19 | 19 | ||
20 | static | 20 | static |
@@ -33,8 +33,7 @@ int open_to_or_warn(int to_fd, const char *filename, int flags, int mode) | |||
33 | return 0; | 33 | return 0; |
34 | } | 34 | } |
35 | 35 | ||
36 | static | 36 | int bbunpack(char **argv, |
37 | int unpack(char **argv, | ||
38 | char* (*make_new_name)(char *filename), | 37 | char* (*make_new_name)(char *filename), |
39 | USE_DESKTOP(long long) int (*unpacker)(void) | 38 | USE_DESKTOP(long long) int (*unpacker)(void) |
40 | ) | 39 | ) |
@@ -173,7 +172,7 @@ int bunzip2_main(int argc, char **argv) | |||
173 | if (applet_name[2] == 'c') | 172 | if (applet_name[2] == 'c') |
174 | option_mask32 |= OPT_STDOUT; | 173 | option_mask32 |= OPT_STDOUT; |
175 | 174 | ||
176 | return unpack(argv, make_new_name_bunzip2, unpack_bunzip2); | 175 | return bbunpack(argv, make_new_name_bunzip2, unpack_bunzip2); |
177 | } | 176 | } |
178 | 177 | ||
179 | #endif | 178 | #endif |
@@ -267,13 +266,13 @@ USE_DESKTOP(long long) int unpack_gunzip(void) | |||
267 | int gunzip_main(int argc, char **argv); | 266 | int gunzip_main(int argc, char **argv); |
268 | int gunzip_main(int argc, char **argv) | 267 | int gunzip_main(int argc, char **argv) |
269 | { | 268 | { |
270 | getopt32(argc, argv, "cftdv"); | 269 | getopt32(argc, argv, "cfvdt"); |
271 | argv += optind; | 270 | argv += optind; |
272 | /* if called as zcat */ | 271 | /* if called as zcat */ |
273 | if (applet_name[1] == 'c') | 272 | if (applet_name[1] == 'c') |
274 | option_mask32 |= OPT_STDOUT; | 273 | option_mask32 |= OPT_STDOUT; |
275 | 274 | ||
276 | return unpack(argv, make_new_name_gunzip, unpack_gunzip); | 275 | return bbunpack(argv, make_new_name_gunzip, unpack_gunzip); |
277 | } | 276 | } |
278 | 277 | ||
279 | #endif | 278 | #endif |
@@ -311,7 +310,7 @@ int unlzma_main(int argc, char **argv) | |||
311 | if (applet_name[4] == 'c') | 310 | if (applet_name[4] == 'c') |
312 | option_mask32 |= OPT_STDOUT; | 311 | option_mask32 |= OPT_STDOUT; |
313 | 312 | ||
314 | return unpack(argv, make_new_name_unlzma, unpack_unlzma); | 313 | return bbunpack(argv, make_new_name_unlzma, unpack_unlzma); |
315 | } | 314 | } |
316 | 315 | ||
317 | #endif | 316 | #endif |
@@ -350,7 +349,7 @@ int uncompress_main(int argc, char **argv) | |||
350 | getopt32(argc, argv, "cf"); | 349 | getopt32(argc, argv, "cf"); |
351 | argv += optind; | 350 | argv += optind; |
352 | 351 | ||
353 | return unpack(argv, make_new_name_uncompress, unpack_uncompress); | 352 | return bbunpack(argv, make_new_name_uncompress, unpack_uncompress); |
354 | } | 353 | } |
355 | 354 | ||
356 | #endif | 355 | #endif |
diff --git a/archival/gzip.c b/archival/gzip.c index c8444ac25..90075272d 100644 --- a/archival/gzip.c +++ b/archival/gzip.c | |||
@@ -2074,6 +2074,7 @@ static void zip(int in, int out) | |||
2074 | 2074 | ||
2075 | 2075 | ||
2076 | /* ======================================================================== */ | 2076 | /* ======================================================================== */ |
2077 | #if 0 | ||
2077 | static void abort_gzip(int ATTRIBUTE_UNUSED ignored) | 2078 | static void abort_gzip(int ATTRIBUTE_UNUSED ignored) |
2078 | { | 2079 | { |
2079 | exit(1); | 2080 | exit(1); |
@@ -2082,92 +2083,6 @@ static void abort_gzip(int ATTRIBUTE_UNUSED ignored) | |||
2082 | int gzip_main(int argc, char **argv); | 2083 | int gzip_main(int argc, char **argv); |
2083 | int gzip_main(int argc, char **argv) | 2084 | int gzip_main(int argc, char **argv) |
2084 | { | 2085 | { |
2085 | enum { | ||
2086 | OPT_tostdout = 0x1, | ||
2087 | OPT_force = 0x2, | ||
2088 | }; | ||
2089 | |||
2090 | unsigned opt; | ||
2091 | int inFileNum; | ||
2092 | int outFileNum; | ||
2093 | int i; | ||
2094 | struct stat statBuf; | ||
2095 | |||
2096 | opt = getopt32(argc, argv, "cf123456789qv" USE_GUNZIP("d")); | ||
2097 | //if (opt & 0x1) // -c | ||
2098 | //if (opt & 0x2) // -f | ||
2099 | /* Ignore 1-9 (compression level) options */ | ||
2100 | //if (opt & 0x4) // -1 | ||
2101 | //if (opt & 0x8) // -2 | ||
2102 | //if (opt & 0x10) // -3 | ||
2103 | //if (opt & 0x20) // -4 | ||
2104 | //if (opt & 0x40) // -5 | ||
2105 | //if (opt & 0x80) // -6 | ||
2106 | //if (opt & 0x100) // -7 | ||
2107 | //if (opt & 0x200) // -8 | ||
2108 | //if (opt & 0x400) // -9 | ||
2109 | //if (opt & 0x800) // -q | ||
2110 | //if (opt & 0x1000) // -v | ||
2111 | #if ENABLE_GUNZIP /* gunzip_main may not be visible... */ | ||
2112 | if (opt & 0x2000) { // -d | ||
2113 | /* FIXME: getopt32 should not depend on optind */ | ||
2114 | optind = 1; | ||
2115 | return gunzip_main(argc, argv); | ||
2116 | } | ||
2117 | #endif | ||
2118 | |||
2119 | /* Comment?? */ | ||
2120 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) { | ||
2121 | signal(SIGINT, abort_gzip); | ||
2122 | } | ||
2123 | #ifdef SIGTERM | ||
2124 | if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { | ||
2125 | signal(SIGTERM, abort_gzip); | ||
2126 | } | ||
2127 | #endif | ||
2128 | #ifdef SIGHUP | ||
2129 | if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { | ||
2130 | signal(SIGHUP, abort_gzip); | ||
2131 | } | ||
2132 | #endif | ||
2133 | |||
2134 | ptr_to_globals = xzalloc(sizeof(struct global1) + sizeof(struct global2)); | ||
2135 | ptr_to_globals++; | ||
2136 | G2.l_desc.dyn_tree = G2.dyn_ltree; | ||
2137 | G2.l_desc.static_tree = G2.static_ltree; | ||
2138 | G2.l_desc.extra_bits = extra_lbits; | ||
2139 | G2.l_desc.extra_base = LITERALS + 1; | ||
2140 | G2.l_desc.elems = L_CODES; | ||
2141 | G2.l_desc.max_length = MAX_BITS; | ||
2142 | //G2.l_desc.max_code = 0; | ||
2143 | |||
2144 | G2.d_desc.dyn_tree = G2.dyn_dtree; | ||
2145 | G2.d_desc.static_tree = G2.static_dtree; | ||
2146 | G2.d_desc.extra_bits = extra_dbits; | ||
2147 | //G2.d_desc.extra_base = 0; | ||
2148 | G2.d_desc.elems = D_CODES; | ||
2149 | G2.d_desc.max_length = MAX_BITS; | ||
2150 | //G2.d_desc.max_code = 0; | ||
2151 | |||
2152 | G2.bl_desc.dyn_tree = G2.bl_tree; | ||
2153 | //G2.bl_desc.static_tree = NULL; | ||
2154 | G2.bl_desc.extra_bits = extra_blbits, | ||
2155 | //G2.bl_desc.extra_base = 0; | ||
2156 | G2.bl_desc.elems = BL_CODES; | ||
2157 | G2.bl_desc.max_length = MAX_BL_BITS; | ||
2158 | //G2.bl_desc.max_code = 0; | ||
2159 | |||
2160 | /* Allocate all global buffers (for DYN_ALLOC option) */ | ||
2161 | ALLOC(uch, G1.l_buf, INBUFSIZ); | ||
2162 | ALLOC(uch, G1.outbuf, OUTBUFSIZ); | ||
2163 | ALLOC(ush, G1.d_buf, DIST_BUFSIZE); | ||
2164 | ALLOC(uch, G1.window, 2L * WSIZE); | ||
2165 | ALLOC(ush, G1.prev, 1L << BITS); | ||
2166 | |||
2167 | /* Initialise the CRC32 table */ | ||
2168 | G1.crc_32_tab = crc32_filltable(0); | ||
2169 | |||
2170 | clear_bufs(); | ||
2171 | 2086 | ||
2172 | if (optind == argc) { | 2087 | if (optind == argc) { |
2173 | G1.time_stamp = 0; | 2088 | G1.time_stamp = 0; |
@@ -2240,3 +2155,87 @@ int gzip_main(int argc, char **argv) | |||
2240 | 2155 | ||
2241 | return 0; //##G1.exit_code; | 2156 | return 0; //##G1.exit_code; |
2242 | } | 2157 | } |
2158 | #endif | ||
2159 | |||
2160 | int bbunpack(char **argv, | ||
2161 | char* (*make_new_name)(char *filename), | ||
2162 | USE_DESKTOP(long long) int (*unpacker)(void) | ||
2163 | ); | ||
2164 | |||
2165 | static | ||
2166 | char* make_new_name_gzip(char *filename) | ||
2167 | { | ||
2168 | return xasprintf("%s.gz", filename); | ||
2169 | } | ||
2170 | |||
2171 | static | ||
2172 | USE_DESKTOP(long long) int pack_gzip(void) | ||
2173 | { | ||
2174 | struct stat s; | ||
2175 | |||
2176 | G1.time_stamp = 0; | ||
2177 | if (!fstat(STDIN_FILENO, &s)) | ||
2178 | G1.time_stamp = s.st_ctime; | ||
2179 | zip(STDIN_FILENO, STDOUT_FILENO); | ||
2180 | return 0; | ||
2181 | } | ||
2182 | |||
2183 | int gzip_main(int argc, char **argv); | ||
2184 | int gzip_main(int argc, char **argv) | ||
2185 | { | ||
2186 | unsigned opt; | ||
2187 | |||
2188 | /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ | ||
2189 | opt = getopt32(argc, argv, "cfv" USE_GUNZIP("d") "q123456789" ); | ||
2190 | option_mask32 &= 0x7; /* Clear -d, ignore -q, -0..9 */ | ||
2191 | //if (opt & 0x1) // -c | ||
2192 | //if (opt & 0x2) // -f | ||
2193 | //if (opt & 0x4) // -v | ||
2194 | #if ENABLE_GUNZIP /* gunzip_main may not be visible... */ | ||
2195 | if (opt & 0x8) { // -d | ||
2196 | /* FIXME: getopt32 should not depend on optind */ | ||
2197 | optind = 1; | ||
2198 | return gunzip_main(argc, argv); | ||
2199 | } | ||
2200 | #endif | ||
2201 | |||
2202 | ptr_to_globals = xzalloc(sizeof(struct global1) + sizeof(struct global2)); | ||
2203 | ptr_to_globals++; | ||
2204 | G2.l_desc.dyn_tree = G2.dyn_ltree; | ||
2205 | G2.l_desc.static_tree = G2.static_ltree; | ||
2206 | G2.l_desc.extra_bits = extra_lbits; | ||
2207 | G2.l_desc.extra_base = LITERALS + 1; | ||
2208 | G2.l_desc.elems = L_CODES; | ||
2209 | G2.l_desc.max_length = MAX_BITS; | ||
2210 | //G2.l_desc.max_code = 0; | ||
2211 | |||
2212 | G2.d_desc.dyn_tree = G2.dyn_dtree; | ||
2213 | G2.d_desc.static_tree = G2.static_dtree; | ||
2214 | G2.d_desc.extra_bits = extra_dbits; | ||
2215 | //G2.d_desc.extra_base = 0; | ||
2216 | G2.d_desc.elems = D_CODES; | ||
2217 | G2.d_desc.max_length = MAX_BITS; | ||
2218 | //G2.d_desc.max_code = 0; | ||
2219 | |||
2220 | G2.bl_desc.dyn_tree = G2.bl_tree; | ||
2221 | //G2.bl_desc.static_tree = NULL; | ||
2222 | G2.bl_desc.extra_bits = extra_blbits, | ||
2223 | //G2.bl_desc.extra_base = 0; | ||
2224 | G2.bl_desc.elems = BL_CODES; | ||
2225 | G2.bl_desc.max_length = MAX_BL_BITS; | ||
2226 | //G2.bl_desc.max_code = 0; | ||
2227 | |||
2228 | /* Allocate all global buffers (for DYN_ALLOC option) */ | ||
2229 | ALLOC(uch, G1.l_buf, INBUFSIZ); | ||
2230 | ALLOC(uch, G1.outbuf, OUTBUFSIZ); | ||
2231 | ALLOC(ush, G1.d_buf, DIST_BUFSIZE); | ||
2232 | ALLOC(uch, G1.window, 2L * WSIZE); | ||
2233 | ALLOC(ush, G1.prev, 1L << BITS); | ||
2234 | |||
2235 | /* Initialise the CRC32 table */ | ||
2236 | G1.crc_32_tab = crc32_filltable(0); | ||
2237 | |||
2238 | clear_bufs(); | ||
2239 | |||
2240 | return bbunpack(argv, make_new_name_gzip, pack_gzip); | ||
2241 | } | ||
diff --git a/docs/keep_data_small.txt b/docs/keep_data_small.txt new file mode 100644 index 000000000..88cc2bc66 --- /dev/null +++ b/docs/keep_data_small.txt | |||
@@ -0,0 +1,88 @@ | |||
1 | Keeping data small | ||
2 | |||
3 | When many applets are compiled into busybox, all rw data and | ||
4 | bss for each applet are concatenated. Including those from libc, | ||
5 | if static bbox is built. When bbox is started, _all_ this data | ||
6 | is allocated, not just that one part for selected applet. | ||
7 | |||
8 | What "allocated" exactly means, depends on arch. | ||
9 | On nommu it's probably bites the most, actually using real | ||
10 | RAM for rwdata and bss. On i386, bss is lazily allocated | ||
11 | by COWed zero pages. Not sure about rwdata - also COW? | ||
12 | |||
13 | Small experiment measures "parasitic" bbox memory consumption. | ||
14 | Here we start 1000 "busybox sleep 10" in parallel. | ||
15 | bbox binary is practically allyesconfig static one, | ||
16 | built against uclibc: | ||
17 | |||
18 | bash-3.2# nmeter '%t %c %b %m %p %[pn]' | ||
19 | 23:17:28 .......... 0 0 168M 0 147 | ||
20 | 23:17:29 .......... 0 0 168M 0 147 | ||
21 | 23:17:30 U......... 0 0 168M 1 147 | ||
22 | 23:17:31 SU........ 0 188k 181M 244 391 | ||
23 | 23:17:32 SSSSUUU... 0 0 223M 757 1147 | ||
24 | 23:17:33 UUU....... 0 0 223M 0 1147 | ||
25 | 23:17:34 U......... 0 0 223M 1 1147 | ||
26 | 23:17:35 .......... 0 0 223M 0 1147 | ||
27 | 23:17:36 .......... 0 0 223M 0 1147 | ||
28 | 23:17:37 S......... 0 0 223M 0 1147 | ||
29 | 23:17:38 .......... 0 0 223M 1 1147 | ||
30 | 23:17:39 .......... 0 0 223M 0 1147 | ||
31 | 23:17:40 .......... 0 0 223M 0 1147 | ||
32 | 23:17:41 .......... 0 0 210M 0 906 | ||
33 | 23:17:42 .......... 0 0 168M 1 147 | ||
34 | 23:17:43 .......... 0 0 168M 0 147 | ||
35 | |||
36 | This requires 55M of memory. Thus 1 trivial busybox applet | ||
37 | takes 55k of userspace memory (nmeter doesn't account for kernel-side | ||
38 | allocations). Definitely can be improved. | ||
39 | |||
40 | Thus we should avoid large global data in our applets, | ||
41 | and should minimize usage of libc functions which implicitly use | ||
42 | such structures in libc. | ||
43 | |||
44 | Example 1 | ||
45 | |||
46 | One example how to reduce global data usage is in | ||
47 | archival/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 | |||
60 | This example completely eliminates globals in that module. | ||
61 | Required memory is allocated in inflate_gunzip() [its main module] | ||
62 | and then passed down to all subroutines which need to access globals | ||
63 | as a parameter. | ||
64 | |||
65 | Example 2 | ||
66 | |||
67 | In case you don't want to pass this additional parameter everywhere, | ||
68 | take a look at archival/gzip.c. Here all global data is replaced by | ||
69 | singe global pointer (ptr_to_globals) to allocated storage. | ||
70 | |||
71 | In order to not duplicate ptr_to_globals in every applet, you can | ||
72 | reuse single common one. It is defined in libbb/messages.c | ||
73 | as void *ptr_to_globals, but is NOT declared in libbb.h. | ||
74 | You first define a struct: | ||
75 | |||
76 | struct my_globals { int a; char buf[1000]; }; | ||
77 | |||
78 | and then declare that ptr_to_globals is a pointer to it: | ||
79 | |||
80 | extern struct my_globals *ptr_to_globals; | ||
81 | #define G (*ptr_to_globals) | ||
82 | |||
83 | Linker magic enures that these two merge into single pointer object. | ||
84 | Now initialize it in <applet>_main(): | ||
85 | |||
86 | ptr_to_globals = xzalloc(sizeof(G)); | ||
87 | |||
88 | and you can reference "globals" by G.a, G.buf and so on, in any function. | ||