diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2008-02-09 17:24:09 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2008-02-09 17:24:09 -0500 |
commit | 9b706aee7d92d6ac3002547aea12e3eaa0a750ae (patch) | |
tree | b1e945b7d6eccd4ef44d80e1f3a4596a4a629c78 | |
parent | b6fbb669c8ef3a112121697ca901c290ccd35eb2 (diff) |
x86: trivial printk optimizations
In arch/x86/boot/printf.c gets rid of unused tail of digits: const char
*digits = "0123456789abcdefghijklmnopqrstuvwxyz"; (we are using 0-9a-f
only)
Uses smaller/faster lowercasing (by ORing with 0x20)
if we know that we work on numbers/digits. Makes
strtoul smaller, and also we are getting rid of
static const char small_digits[] = "0123456789abcdefx";
static const char large_digits[] = "0123456789ABCDEFX";
since this works equally well:
static const char digits[16] = "0123456789ABCDEF";
Size savings:
$ size vmlinux.org vmlinux
text data bss dec hex filename
877320 112252 90112 1079684 107984 vmlinux.org
877048 112252 90112 1079412 107874 vmlinux
It may be also a tiny bit faster because code has less
branches now, but I doubt it is measurable.
[ hugh@veritas.com: uppercase pointers fix ]
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | arch/x86/boot/printf.c | 24 | ||||
-rw-r--r-- | lib/vsprintf.c | 49 |
2 files changed, 41 insertions, 32 deletions
diff --git a/arch/x86/boot/printf.c b/arch/x86/boot/printf.c index 1a09f9309d3c..7e7e890699be 100644 --- a/arch/x86/boot/printf.c +++ b/arch/x86/boot/printf.c | |||
@@ -33,8 +33,8 @@ static int skip_atoi(const char **s) | |||
33 | #define PLUS 4 /* show plus */ | 33 | #define PLUS 4 /* show plus */ |
34 | #define SPACE 8 /* space if plus */ | 34 | #define SPACE 8 /* space if plus */ |
35 | #define LEFT 16 /* left justified */ | 35 | #define LEFT 16 /* left justified */ |
36 | #define SPECIAL 32 /* 0x */ | 36 | #define SMALL 32 /* Must be 32 == 0x20 */ |
37 | #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ | 37 | #define SPECIAL 64 /* 0x */ |
38 | 38 | ||
39 | #define do_div(n,base) ({ \ | 39 | #define do_div(n,base) ({ \ |
40 | int __res; \ | 40 | int __res; \ |
@@ -45,12 +45,16 @@ __res; }) | |||
45 | static char *number(char *str, long num, int base, int size, int precision, | 45 | static char *number(char *str, long num, int base, int size, int precision, |
46 | int type) | 46 | int type) |
47 | { | 47 | { |
48 | char c, sign, tmp[66]; | 48 | /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ |
49 | const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; | 49 | static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ |
50 | |||
51 | char tmp[66]; | ||
52 | char c, sign, locase; | ||
50 | int i; | 53 | int i; |
51 | 54 | ||
52 | if (type & LARGE) | 55 | /* locase = 0 or 0x20. ORing digits or letters with 'locase' |
53 | digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | 56 | * produces same digits or (maybe lowercased) letters */ |
57 | locase = (type & SMALL); | ||
54 | if (type & LEFT) | 58 | if (type & LEFT) |
55 | type &= ~ZEROPAD; | 59 | type &= ~ZEROPAD; |
56 | if (base < 2 || base > 36) | 60 | if (base < 2 || base > 36) |
@@ -81,7 +85,7 @@ static char *number(char *str, long num, int base, int size, int precision, | |||
81 | tmp[i++] = '0'; | 85 | tmp[i++] = '0'; |
82 | else | 86 | else |
83 | while (num != 0) | 87 | while (num != 0) |
84 | tmp[i++] = digits[do_div(num, base)]; | 88 | tmp[i++] = (digits[do_div(num, base)] | locase); |
85 | if (i > precision) | 89 | if (i > precision) |
86 | precision = i; | 90 | precision = i; |
87 | size -= precision; | 91 | size -= precision; |
@@ -95,7 +99,7 @@ static char *number(char *str, long num, int base, int size, int precision, | |||
95 | *str++ = '0'; | 99 | *str++ = '0'; |
96 | else if (base == 16) { | 100 | else if (base == 16) { |
97 | *str++ = '0'; | 101 | *str++ = '0'; |
98 | *str++ = digits[33]; | 102 | *str++ = ('X' | locase); |
99 | } | 103 | } |
100 | } | 104 | } |
101 | if (!(type & LEFT)) | 105 | if (!(type & LEFT)) |
@@ -244,9 +248,9 @@ int vsprintf(char *buf, const char *fmt, va_list args) | |||
244 | base = 8; | 248 | base = 8; |
245 | break; | 249 | break; |
246 | 250 | ||
247 | case 'X': | ||
248 | flags |= LARGE; | ||
249 | case 'x': | 251 | case 'x': |
252 | flags |= SMALL; | ||
253 | case 'X': | ||
250 | base = 16; | 254 | base = 16; |
251 | break; | 255 | break; |
252 | 256 | ||
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 419993f58c6b..fd987b17bda7 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -26,6 +26,9 @@ | |||
26 | #include <asm/page.h> /* for PAGE_SIZE */ | 26 | #include <asm/page.h> /* for PAGE_SIZE */ |
27 | #include <asm/div64.h> | 27 | #include <asm/div64.h> |
28 | 28 | ||
29 | /* Works only for digits and letters, but small and fast */ | ||
30 | #define TOLOWER(x) ((x) | 0x20) | ||
31 | |||
29 | /** | 32 | /** |
30 | * simple_strtoul - convert a string to an unsigned long | 33 | * simple_strtoul - convert a string to an unsigned long |
31 | * @cp: The start of the string | 34 | * @cp: The start of the string |
@@ -41,17 +44,17 @@ unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) | |||
41 | if (*cp == '0') { | 44 | if (*cp == '0') { |
42 | base = 8; | 45 | base = 8; |
43 | cp++; | 46 | cp++; |
44 | if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { | 47 | if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) { |
45 | cp++; | 48 | cp++; |
46 | base = 16; | 49 | base = 16; |
47 | } | 50 | } |
48 | } | 51 | } |
49 | } else if (base == 16) { | 52 | } else if (base == 16) { |
50 | if (cp[0] == '0' && toupper(cp[1]) == 'X') | 53 | if (cp[0] == '0' && TOLOWER(cp[1]) == 'x') |
51 | cp += 2; | 54 | cp += 2; |
52 | } | 55 | } |
53 | while (isxdigit(*cp) && | 56 | while (isxdigit(*cp) && |
54 | (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { | 57 | (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) { |
55 | result = result*base + value; | 58 | result = result*base + value; |
56 | cp++; | 59 | cp++; |
57 | } | 60 | } |
@@ -92,17 +95,17 @@ unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) | |||
92 | if (*cp == '0') { | 95 | if (*cp == '0') { |
93 | base = 8; | 96 | base = 8; |
94 | cp++; | 97 | cp++; |
95 | if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { | 98 | if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) { |
96 | cp++; | 99 | cp++; |
97 | base = 16; | 100 | base = 16; |
98 | } | 101 | } |
99 | } | 102 | } |
100 | } else if (base == 16) { | 103 | } else if (base == 16) { |
101 | if (cp[0] == '0' && toupper(cp[1]) == 'X') | 104 | if (cp[0] == '0' && TOLOWER(cp[1]) == 'x') |
102 | cp += 2; | 105 | cp += 2; |
103 | } | 106 | } |
104 | while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) | 107 | while (isxdigit(*cp) |
105 | ? toupper(*cp) : *cp)-'A'+10) < base) { | 108 | && (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) { |
106 | result = result*base + value; | 109 | result = result*base + value; |
107 | cp++; | 110 | cp++; |
108 | } | 111 | } |
@@ -360,24 +363,25 @@ static noinline char* put_dec(char *buf, unsigned long long num) | |||
360 | #define PLUS 4 /* show plus */ | 363 | #define PLUS 4 /* show plus */ |
361 | #define SPACE 8 /* space if plus */ | 364 | #define SPACE 8 /* space if plus */ |
362 | #define LEFT 16 /* left justified */ | 365 | #define LEFT 16 /* left justified */ |
363 | #define SPECIAL 32 /* 0x */ | 366 | #define SMALL 32 /* Must be 32 == 0x20 */ |
364 | #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ | 367 | #define SPECIAL 64 /* 0x */ |
365 | 368 | ||
366 | static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type) | 369 | static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type) |
367 | { | 370 | { |
368 | char sign,tmp[66]; | 371 | /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ |
369 | const char *digits; | 372 | static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ |
370 | /* we are called with base 8, 10 or 16, only, thus don't need "g..." */ | 373 | |
371 | static const char small_digits[] = "0123456789abcdefx"; /* "ghijklmnopqrstuvwxyz"; */ | 374 | char tmp[66]; |
372 | static const char large_digits[] = "0123456789ABCDEFX"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ | 375 | char sign; |
376 | char locase; | ||
373 | int need_pfx = ((type & SPECIAL) && base != 10); | 377 | int need_pfx = ((type & SPECIAL) && base != 10); |
374 | int i; | 378 | int i; |
375 | 379 | ||
376 | digits = (type & LARGE) ? large_digits : small_digits; | 380 | /* locase = 0 or 0x20. ORing digits or letters with 'locase' |
381 | * produces same digits or (maybe lowercased) letters */ | ||
382 | locase = (type & SMALL); | ||
377 | if (type & LEFT) | 383 | if (type & LEFT) |
378 | type &= ~ZEROPAD; | 384 | type &= ~ZEROPAD; |
379 | if (base < 2 || base > 36) | ||
380 | return NULL; | ||
381 | sign = 0; | 385 | sign = 0; |
382 | if (type & SIGN) { | 386 | if (type & SIGN) { |
383 | if ((signed long long) num < 0) { | 387 | if ((signed long long) num < 0) { |
@@ -404,7 +408,7 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
404 | tmp[i++] = '0'; | 408 | tmp[i++] = '0'; |
405 | /* Generic code, for any base: | 409 | /* Generic code, for any base: |
406 | else do { | 410 | else do { |
407 | tmp[i++] = digits[do_div(num,base)]; | 411 | tmp[i++] = (digits[do_div(num,base)] | locase); |
408 | } while (num != 0); | 412 | } while (num != 0); |
409 | */ | 413 | */ |
410 | else if (base != 10) { /* 8 or 16 */ | 414 | else if (base != 10) { /* 8 or 16 */ |
@@ -412,7 +416,7 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
412 | int shift = 3; | 416 | int shift = 3; |
413 | if (base == 16) shift = 4; | 417 | if (base == 16) shift = 4; |
414 | do { | 418 | do { |
415 | tmp[i++] = digits[((unsigned char)num) & mask]; | 419 | tmp[i++] = (digits[((unsigned char)num) & mask] | locase); |
416 | num >>= shift; | 420 | num >>= shift; |
417 | } while (num); | 421 | } while (num); |
418 | } else { /* base 10 */ | 422 | } else { /* base 10 */ |
@@ -444,7 +448,7 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
444 | ++buf; | 448 | ++buf; |
445 | if (base == 16) { | 449 | if (base == 16) { |
446 | if (buf < end) | 450 | if (buf < end) |
447 | *buf = digits[16]; /* for arbitrary base: digits[33]; */ | 451 | *buf = ('X' | locase); |
448 | ++buf; | 452 | ++buf; |
449 | } | 453 | } |
450 | } | 454 | } |
@@ -644,6 +648,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) | |||
644 | continue; | 648 | continue; |
645 | 649 | ||
646 | case 'p': | 650 | case 'p': |
651 | flags |= SMALL; | ||
647 | if (field_width == -1) { | 652 | if (field_width == -1) { |
648 | field_width = 2*sizeof(void *); | 653 | field_width = 2*sizeof(void *); |
649 | flags |= ZEROPAD; | 654 | flags |= ZEROPAD; |
@@ -680,9 +685,9 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) | |||
680 | base = 8; | 685 | base = 8; |
681 | break; | 686 | break; |
682 | 687 | ||
683 | case 'X': | ||
684 | flags |= LARGE; | ||
685 | case 'x': | 688 | case 'x': |
689 | flags |= SMALL; | ||
690 | case 'X': | ||
686 | base = 16; | 691 | base = 16; |
687 | break; | 692 | break; |
688 | 693 | ||