aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-01-29 13:22:48 +0000
committerDenys Vlasenko <vda.linux@googlemail.com>2021-02-02 14:16:38 +0100
commit59120c330330467c9e6aaec6d4ca8295baa653af (patch)
treed22982ca2eac6d933d9e68bb3aa81d3e9032e49b
parente8fe9f96356a6b19ec907ea30cffc829c539a7ff (diff)
downloadbusybox-w32-59120c330330467c9e6aaec6d4ca8295baa653af.tar.gz
busybox-w32-59120c330330467c9e6aaec6d4ca8295baa653af.tar.bz2
busybox-w32-59120c330330467c9e6aaec6d4ca8295baa653af.zip
libbb: code shrink and speed up find_applet_by_name()
find_applet_by_name() determines the appropriate range of applet indices to check for the given name and performs a linear search in applet_names[]. Revise the code so the index of the upper bound of the range, 'max', isn't calculated. Instead check the value of the first non-matching character to see if we've reached the end of the range. This new code speeds up the time to find a valid applet name by 6% and halves the time to detect that a given name is invalid. The average time to detect an invalid name is now the same as for a valid one. function old new delta find_applet_by_name 155 133 -22 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-22) Total: -22 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--libbb/appletlib.c96
1 files changed, 17 insertions, 79 deletions
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 5f59f1273..542211255 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -176,7 +176,7 @@ void FAST_FUNC bb_show_usage(void)
176 176
177int FAST_FUNC find_applet_by_name(const char *name) 177int FAST_FUNC find_applet_by_name(const char *name)
178{ 178{
179 unsigned i, max; 179 unsigned i;
180 int j; 180 int j;
181 const char *p; 181 const char *p;
182 182
@@ -200,105 +200,43 @@ int FAST_FUNC find_applet_by_name(const char *name)
200#endif 200#endif
201 201
202 p = applet_names; 202 p = applet_names;
203 i = 0;
204#if KNOWN_APPNAME_OFFSETS <= 0 203#if KNOWN_APPNAME_OFFSETS <= 0
205 max = NUM_APPLETS; 204 i = 0;
206#else 205#else
207 max = NUM_APPLETS * KNOWN_APPNAME_OFFSETS; 206 i = NUM_APPLETS * (KNOWN_APPNAME_OFFSETS - 1);
208 for (j = ARRAY_SIZE(applet_nameofs)-1; j >= 0; j--) { 207 for (j = ARRAY_SIZE(applet_nameofs)-1; j >= 0; j--) {
209 const char *pp = applet_names + applet_nameofs[j]; 208 const char *pp = applet_names + applet_nameofs[j];
210 if (strcmp(name, pp) >= 0) { 209 if (strcmp(name, pp) >= 0) {
211 //bb_error_msg("name:'%s' >= pp:'%s'", name, pp); 210 //bb_error_msg("name:'%s' >= pp:'%s'", name, pp);
212 p = pp; 211 p = pp;
213 i = max - NUM_APPLETS;
214 break; 212 break;
215 } 213 }
216 max -= NUM_APPLETS; 214 i -= NUM_APPLETS;
217 } 215 }
218 max /= (unsigned)KNOWN_APPNAME_OFFSETS;
219 i /= (unsigned)KNOWN_APPNAME_OFFSETS; 216 i /= (unsigned)KNOWN_APPNAME_OFFSETS;
220 //bb_error_msg("name:'%s' starting from:'%s' i:%u max:%u", name, p, i, max); 217 //bb_error_msg("name:'%s' starting from:'%s' i:%u", name, p, i);
221#endif 218#endif
222 219
223 /* Open-coded linear search without strcmp/strlen calls for speed */ 220 /* Open-coded linear search without strcmp/strlen calls for speed */
224 221 while (*p) {
225#if 0 /*BB_UNALIGNED_MEMACCESS_OK && BB_LITTLE_ENDIAN*/ 222 /* Do we see "name\0" at current position in applet_names? */
226 /* skip "[\0" name, it's surely not it */ 223 for (j = 0; *p == name[j]; ++j) {
227 if (ENABLE_TEST && LONE_CHAR(p, '[')) 224 if (*p++ == '\0') {
228 i++, p += 2;
229 /* All remaining applet names in p[] are at least 2 chars long */
230 /* name[] is also at least 2 chars long */
231
232 n32 = (name[0] << 0) | (name[1] << 8) | (name[2] << 16);
233 while (i < max) {
234 uint32_t p32;
235 char ch;
236
237 /* Quickly check match of the first 3 bytes */
238 move_from_unaligned32(p32, p);
239 p += 3;
240 if ((p32 & 0x00ffffff) != n32) {
241 /* Most likely case: 3 first bytes do not match */
242 i++;
243 if ((p32 & 0x00ff0000) == '\0')
244 continue; // p[2] was NUL
245 p++;
246 if ((p32 & 0xff000000) == '\0')
247 continue; // p[3] was NUL
248 /* p[0..3] aren't matching and none is NUL, check the rest */
249 while (*p++ != '\0')
250 continue;
251 continue;
252 }
253
254 /* Unlikely branch: first 3 bytes ([0..2]) match */
255 if ((p32 & 0x00ff0000) == '\0') {
256 /* name is 2-byte long, it is full match */
257 //bb_error_msg("found:'%s' i:%u", name, i);
258 return i;
259 }
260 /* Check remaining bytes [3..NUL] */
261 ch = (p32 >> 24);
262 j = 3;
263 while (ch == name[j]) {
264 if (ch == '\0') {
265 //bb_error_msg("found:'%s' i:%u", name, i);
266 return i;
267 }
268 ch = *++p;
269 j++;
270 }
271 /* Not a match. Skip it, including NUL */
272 while (ch != '\0')
273 ch = *++p;
274 p++;
275 i++;
276 }
277 return -1;
278#else
279 while (i < max) {
280 char ch;
281 j = 0;
282 /* Do we see "name\0" in applet_names[p] position? */
283 while ((ch = *p) == name[j]) {
284 if (ch == '\0') {
285 //bb_error_msg("found:'%s' i:%u", name, i); 225 //bb_error_msg("found:'%s' i:%u", name, i);
286 return i; /* yes */ 226 return i; /* yes */
287 } 227 }
288 p++;
289 j++;
290 } 228 }
291 /* No. 229 /* No. Have we gone too far, alphabetically? */
292 * p => 1st non-matching char in applet_names[], 230 if (*p > name[j]) {
293 * skip to and including NUL. 231 //bb_error_msg("break:'%s' i:%u", name, i);
294 */ 232 break;
295 while (ch != '\0') 233 }
296 ch = *++p; 234 /* No. Move to the start of the next applet name. */
297 p++; 235 while (*p++ != '\0')
236 continue;
298 i++; 237 i++;
299 } 238 }
300 return -1; 239 return -1;
301#endif
302} 240}
303 241
304 242