diff options
author | Ron Yorston <rmy@pobox.com> | 2016-03-30 00:42:05 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-03-30 00:44:11 +0200 |
commit | 610c4c385b38280c7bde7a48d95ec019cbfe1ab4 (patch) | |
tree | 82ad4366ce9e927f64efa89d178c4dd2bfea1435 /libbb/appletlib.c | |
parent | 9844d7e830a2c55421e27e8828d2067c50f57c23 (diff) | |
download | busybox-w32-610c4c385b38280c7bde7a48d95ec019cbfe1ab4.tar.gz busybox-w32-610c4c385b38280c7bde7a48d95ec019cbfe1ab4.tar.bz2 busybox-w32-610c4c385b38280c7bde7a48d95ec019cbfe1ab4.zip |
applet_tables: save space by removing applet name offsets
The array applet_nameofs consumes two bytes per applet. It encodes
nofork/noexec flags
suid flags
the offset of the applet name in the applet_name string
Change the applet_table build tool to store the flags in two separate
arrays (applet_flags and applet_suid). Replace applet_nameofs[] with a
smaller version that only stores a limited number of offsets.
This requires changes to the macros APPLET_IS_NOFORK, APPLET_IS_NOEXEC
and APPLET_SUID.
According to Valgrind the original find_applet_by_name required
353 cycles per call, averaged over all names. Adjusting the number
of known offsets allows space to be traded off against execution time:
KNOWN_OFFSETS cycles bytes (wrt KNOWN_OFFSETS = 0)
0 9057 -
2 4604 32
4 2407 75
8 1342 98
16 908 130
32 884 194
This patch uses KNOWN_OFFSETS = 8.
v2:
Remove some dead code from the applet_table tool;
Treat the applet in the middle of the table as a special case.
v3:
Use the middle applet to adjust the start of the linear search as
well as the last applet found.
v4:
Use an augmented linear search in find_applet_by_name.
Drop the special treatment of the middle name from get_applet_name:
most of the advantage now derives from the last stored value.
v5:
Don't store index in applet_nameofs, it can be calculated.
v6:
Tweaks by Denys
function old new delta
find_applet_by_name 25 125 +100
applet_suid - 92 +92
run_applet_no_and_exit 452 460 +8
run_applet_and_exit 695 697 +2
applet_name_compare 31 - -31
applet_nameofs 734 14 -720
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 3/1 up/down: 202/-751) Total: -549 bytes
text data bss dec hex filename
925464 906 17160 943530 e65aa busybox_old
924915 906 17160 942981 e6385 busybox_unstripped
Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb/appletlib.c')
-rw-r--r-- | libbb/appletlib.c | 82 |
1 files changed, 54 insertions, 28 deletions
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 95e589e74..aeaf238f1 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
@@ -139,36 +139,56 @@ void FAST_FUNC bb_show_usage(void) | |||
139 | xfunc_die(); | 139 | xfunc_die(); |
140 | } | 140 | } |
141 | 141 | ||
142 | #if NUM_APPLETS > 8 | ||
143 | static int applet_name_compare(const void *name, const void *idx) | ||
144 | { | ||
145 | int i = (int)(ptrdiff_t)idx - 1; | ||
146 | return strcmp(name, APPLET_NAME(i)); | ||
147 | } | ||
148 | #endif | ||
149 | int FAST_FUNC find_applet_by_name(const char *name) | 142 | int FAST_FUNC find_applet_by_name(const char *name) |
150 | { | 143 | { |
151 | #if NUM_APPLETS > 8 | 144 | unsigned i, max; |
152 | /* Do a binary search to find the applet entry given the name. */ | 145 | int j; |
153 | const char *p; | 146 | const char *p; |
154 | p = bsearch(name, (void*)(ptrdiff_t)1, ARRAY_SIZE(applet_main), 1, applet_name_compare); | 147 | |
155 | /* | 148 | p = applet_names; |
156 | * if (!p) return -1; | 149 | i = 0; |
157 | * ^^^^^^^^^^^^^^^^^^ the code below will do this if p == NULL :) | 150 | #if KNOWN_APPNAME_OFFSETS <= 0 |
158 | */ | 151 | max = NUM_APPLETS; |
159 | return (int)(ptrdiff_t)p - 1; | ||
160 | #else | 152 | #else |
161 | /* A version which does not pull in bsearch */ | 153 | max = NUM_APPLETS * KNOWN_APPNAME_OFFSETS; |
162 | int i = 0; | 154 | for (j = ARRAY_SIZE(applet_nameofs)-1; j >= 0; j--) { |
163 | const char *p = applet_names; | 155 | const char *pp = applet_names + applet_nameofs[j]; |
164 | while (i < NUM_APPLETS) { | 156 | if (strcmp(name, pp) >= 0) { |
165 | if (strcmp(name, p) == 0) | 157 | //bb_error_msg("name:'%s' >= pp:'%s'", name, pp); |
166 | return i; | 158 | p = pp; |
167 | p += strlen(p) + 1; | 159 | i = max - NUM_APPLETS; |
160 | break; | ||
161 | } | ||
162 | max -= NUM_APPLETS; | ||
163 | } | ||
164 | max /= (unsigned)KNOWN_APPNAME_OFFSETS; | ||
165 | i /= (unsigned)KNOWN_APPNAME_OFFSETS; | ||
166 | //bb_error_msg("name:'%s' starting from:'%s' i:%u max:%u", name, p, i, max); | ||
167 | #endif | ||
168 | |||
169 | /* Open-coding without strcmp/strlen calls for speed */ | ||
170 | while (i < max) { | ||
171 | char ch; | ||
172 | j = 0; | ||
173 | /* Do we see "name\0" in applet_names[p] position? */ | ||
174 | while ((ch = *p) == name[j]) { | ||
175 | if (ch == '\0') { | ||
176 | //bb_error_msg("found:'%s' i:%u", name, i); | ||
177 | return i; /* yes */ | ||
178 | } | ||
179 | p++; | ||
180 | j++; | ||
181 | } | ||
182 | /* No. | ||
183 | * p => 1st non-matching char in applet_names[], | ||
184 | * skip to and including NUL. | ||
185 | */ | ||
186 | while (ch != '\0') | ||
187 | ch = *++p; | ||
188 | p++; | ||
168 | i++; | 189 | i++; |
169 | } | 190 | } |
170 | return -1; | 191 | return -1; |
171 | #endif | ||
172 | } | 192 | } |
173 | 193 | ||
174 | 194 | ||
@@ -583,6 +603,7 @@ static void install_links(const char *busybox, int use_symbolic_links, | |||
583 | * busybox.h::bb_install_loc_t, or else... */ | 603 | * busybox.h::bb_install_loc_t, or else... */ |
584 | int (*lf)(const char *, const char *); | 604 | int (*lf)(const char *, const char *); |
585 | char *fpc; | 605 | char *fpc; |
606 | const char *appname = applet_names; | ||
586 | unsigned i; | 607 | unsigned i; |
587 | int rc; | 608 | int rc; |
588 | 609 | ||
@@ -593,7 +614,7 @@ static void install_links(const char *busybox, int use_symbolic_links, | |||
593 | for (i = 0; i < ARRAY_SIZE(applet_main); i++) { | 614 | for (i = 0; i < ARRAY_SIZE(applet_main); i++) { |
594 | fpc = concat_path_file( | 615 | fpc = concat_path_file( |
595 | custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)], | 616 | custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)], |
596 | APPLET_NAME(i)); | 617 | appname); |
597 | // debug: bb_error_msg("%slinking %s to busybox", | 618 | // debug: bb_error_msg("%slinking %s to busybox", |
598 | // use_symbolic_links ? "sym" : "", fpc); | 619 | // use_symbolic_links ? "sym" : "", fpc); |
599 | rc = lf(busybox, fpc); | 620 | rc = lf(busybox, fpc); |
@@ -601,6 +622,8 @@ static void install_links(const char *busybox, int use_symbolic_links, | |||
601 | bb_simple_perror_msg(fpc); | 622 | bb_simple_perror_msg(fpc); |
602 | } | 623 | } |
603 | free(fpc); | 624 | free(fpc); |
625 | while (*appname++ != '\0') | ||
626 | continue; | ||
604 | } | 627 | } |
605 | } | 628 | } |
606 | # else | 629 | # else |
@@ -754,7 +777,7 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) | |||
754 | 777 | ||
755 | /* Reinit some shared global data */ | 778 | /* Reinit some shared global data */ |
756 | xfunc_error_retval = EXIT_FAILURE; | 779 | xfunc_error_retval = EXIT_FAILURE; |
757 | applet_name = APPLET_NAME(applet_no); | 780 | applet_name = bb_get_last_path_component_nostrip(argv[0]); |
758 | 781 | ||
759 | /* Special case. POSIX says "test --help" | 782 | /* Special case. POSIX says "test --help" |
760 | * should be no different from e.g. "test --foo". | 783 | * should be no different from e.g. "test --foo". |
@@ -785,11 +808,14 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) | |||
785 | 808 | ||
786 | void FAST_FUNC run_applet_and_exit(const char *name, char **argv) | 809 | void FAST_FUNC run_applet_and_exit(const char *name, char **argv) |
787 | { | 810 | { |
788 | int applet = find_applet_by_name(name); | 811 | int applet; |
789 | if (applet >= 0) | 812 | |
790 | run_applet_no_and_exit(applet, argv); | ||
791 | if (is_prefixed_with(name, "busybox")) | 813 | if (is_prefixed_with(name, "busybox")) |
792 | exit(busybox_main(argv)); | 814 | exit(busybox_main(argv)); |
815 | /* find_applet_by_name() search is more expensive, so goes second */ | ||
816 | applet = find_applet_by_name(name); | ||
817 | if (applet >= 0) | ||
818 | run_applet_no_and_exit(applet, argv); | ||
793 | } | 819 | } |
794 | 820 | ||
795 | #endif /* !defined(SINGLE_APPLET_MAIN) */ | 821 | #endif /* !defined(SINGLE_APPLET_MAIN) */ |