Merge "10x printf speedup."
This commit is contained in:
commit
c18f55ca2b
|
@ -196,3 +196,12 @@ static void BM_stdio_printf_d(benchmark::State& state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIONIC_BENCHMARK(BM_stdio_printf_d);
|
BIONIC_BENCHMARK(BM_stdio_printf_d);
|
||||||
|
|
||||||
|
static void BM_stdio_printf_1$s(benchmark::State& state) {
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
snprintf(buf, sizeof(buf), "this is a more typical error message with detail: %1$s",
|
||||||
|
"No such file or directory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BIONIC_BENCHMARK(BM_stdio_printf_1$s);
|
||||||
|
|
|
@ -197,6 +197,9 @@
|
||||||
<fn>
|
<fn>
|
||||||
<name>BM_stdio_printf_d</name>
|
<name>BM_stdio_printf_d</name>
|
||||||
</fn>
|
</fn>
|
||||||
|
<fn>
|
||||||
|
<name>BM_stdio_printf_1$s</name>
|
||||||
|
</fn>
|
||||||
<fn>
|
<fn>
|
||||||
<name>BM_string_memcmp</name>
|
<name>BM_string_memcmp</name>
|
||||||
<args>AT_ALIGNED_TWOBUF</args>
|
<args>AT_ALIGNED_TWOBUF</args>
|
||||||
|
|
|
@ -251,7 +251,6 @@ static int exponent(CharT* p0, int exp, int fmtch) {
|
||||||
#define MAXINT 0x1000 /* largest integer size (intmax_t) */
|
#define MAXINT 0x1000 /* largest integer size (intmax_t) */
|
||||||
|
|
||||||
int __vfprintf(FILE* fp, const char* fmt0, __va_list ap) {
|
int __vfprintf(FILE* fp, const char* fmt0, __va_list ap) {
|
||||||
char* fmt; /* format string */
|
|
||||||
int ch; /* character from fmt */
|
int ch; /* character from fmt */
|
||||||
int n, n2; /* handy integers (short term usage) */
|
int n, n2; /* handy integers (short term usage) */
|
||||||
char* cp; /* handy char pointer (short term usage) */
|
char* cp; /* handy char pointer (short term usage) */
|
||||||
|
@ -261,7 +260,6 @@ int __vfprintf(FILE* fp, const char* fmt0, __va_list ap) {
|
||||||
int width; /* width from format (%8d), or 0 */
|
int width; /* width from format (%8d), or 0 */
|
||||||
int prec; /* precision from format; <0 for N/A */
|
int prec; /* precision from format; <0 for N/A */
|
||||||
char sign; /* sign prefix (' ', '+', '-', or \0) */
|
char sign; /* sign prefix (' ', '+', '-', or \0) */
|
||||||
wchar_t wc;
|
|
||||||
mbstate_t ps;
|
mbstate_t ps;
|
||||||
/*
|
/*
|
||||||
* We can decompose the printed representation of floating
|
* We can decompose the printed representation of floating
|
||||||
|
@ -316,10 +314,12 @@ int __vfprintf(FILE* fp, const char* fmt0, __va_list ap) {
|
||||||
* below longer.
|
* below longer.
|
||||||
*/
|
*/
|
||||||
#define PADSIZE 16 /* pad chunk size */
|
#define PADSIZE 16 /* pad chunk size */
|
||||||
static char blanks[PADSIZE] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
|
static CHAR_TYPE blanks[PADSIZE] = {
|
||||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };
|
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
|
||||||
static char zeroes[PADSIZE] = { '0', '0', '0', '0', '0', '0', '0', '0',
|
};
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0' };
|
static CHAR_TYPE zeroes[PADSIZE] = {
|
||||||
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'
|
||||||
|
};
|
||||||
|
|
||||||
static const char xdigs_lower[] = "0123456789abcdef";
|
static const char xdigs_lower[] = "0123456789abcdef";
|
||||||
static const char xdigs_upper[] = "0123456789ABCDEF";
|
static const char xdigs_upper[] = "0123456789ABCDEF";
|
||||||
|
@ -444,17 +444,19 @@ int __vfprintf(FILE* fp, const char* fmt0, __va_list ap) {
|
||||||
((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : (nextarg++, va_arg(ap, type)))
|
((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : (nextarg++, va_arg(ap, type)))
|
||||||
|
|
||||||
_SET_ORIENTATION(fp, -1);
|
_SET_ORIENTATION(fp, -1);
|
||||||
/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
|
|
||||||
|
// Writing "" to a read only file returns EOF, not 0.
|
||||||
if (cantwrite(fp)) {
|
if (cantwrite(fp)) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return (EOF);
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* optimise fprintf(stderr) (and other unbuffered Unix files) */
|
// Optimize writes to stderr and other unbuffered files).
|
||||||
if ((fp->_flags & (__SNBF | __SWR | __SRW)) == (__SNBF | __SWR) && fp->_file >= 0)
|
if ((fp->_flags & (__SNBF | __SWR | __SRW)) == (__SNBF | __SWR) && fp->_file >= 0) {
|
||||||
return (__sbprintf(fp, fmt0, ap));
|
return (__sbprintf(fp, fmt0, ap));
|
||||||
|
}
|
||||||
|
|
||||||
fmt = (char*)fmt0;
|
CHAR_TYPE* fmt = const_cast<CHAR_TYPE*>(fmt0);
|
||||||
argtable = NULL;
|
argtable = NULL;
|
||||||
nextarg = 1;
|
nextarg = 1;
|
||||||
va_copy(orgap, ap);
|
va_copy(orgap, ap);
|
||||||
|
@ -469,25 +471,14 @@ int __vfprintf(FILE* fp, const char* fmt0, __va_list ap) {
|
||||||
* Scan the format for conversions (`%' character).
|
* Scan the format for conversions (`%' character).
|
||||||
*/
|
*/
|
||||||
for (;;) {
|
for (;;) {
|
||||||
cp = fmt;
|
for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) continue;
|
||||||
while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
|
|
||||||
fmt += n;
|
|
||||||
if (wc == '%') {
|
|
||||||
fmt--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (n < 0) {
|
|
||||||
ret = -1;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (fmt != cp) {
|
if (fmt != cp) {
|
||||||
ptrdiff_t m = fmt - cp;
|
ptrdiff_t m = fmt - cp;
|
||||||
if (m < 0 || m > INT_MAX - ret) goto overflow;
|
if (m < 0 || m > INT_MAX - ret) goto overflow;
|
||||||
PRINT(cp, m);
|
PRINT(cp, m);
|
||||||
ret += m;
|
ret += m;
|
||||||
}
|
}
|
||||||
if (n == 0) goto done;
|
if (ch == '\0') goto done;
|
||||||
fmt++; /* skip over '%' */
|
fmt++; /* skip over '%' */
|
||||||
|
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
@ -1062,12 +1053,10 @@ finish:
|
||||||
* used since we are attempting to make snprintf thread safe, and alloca is
|
* used since we are attempting to make snprintf thread safe, and alloca is
|
||||||
* problematic since we have nested functions..)
|
* problematic since we have nested functions..)
|
||||||
*/
|
*/
|
||||||
static int __find_arguments(const char* fmt0, va_list ap, union arg** argtable,
|
static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable,
|
||||||
size_t* argtablesiz) {
|
size_t* argtablesiz) {
|
||||||
char* fmt; /* format string */
|
|
||||||
int ch; /* character from fmt */
|
int ch; /* character from fmt */
|
||||||
int n, n2; /* handy integer (short term usage) */
|
int n, n2; /* handy integer (short term usage) */
|
||||||
char* cp; /* handy char pointer (short term usage) */
|
|
||||||
int flags; /* flags as above */
|
int flags; /* flags as above */
|
||||||
unsigned char* typetable; /* table of types */
|
unsigned char* typetable; /* table of types */
|
||||||
unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
|
unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
|
||||||
|
@ -1075,8 +1064,6 @@ static int __find_arguments(const char* fmt0, va_list ap, union arg** argtable,
|
||||||
int tablemax; /* largest used index in table */
|
int tablemax; /* largest used index in table */
|
||||||
int nextarg; /* 1-based argument index */
|
int nextarg; /* 1-based argument index */
|
||||||
int ret = 0; /* return value */
|
int ret = 0; /* return value */
|
||||||
wchar_t wc;
|
|
||||||
mbstate_t ps;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add an argument type to the table, expanding if necessary.
|
* Add an argument type to the table, expanding if necessary.
|
||||||
|
@ -1135,28 +1122,20 @@ static int __find_arguments(const char* fmt0, va_list ap, union arg** argtable,
|
||||||
} else { \
|
} else { \
|
||||||
ADDTYPE(T_INT); \
|
ADDTYPE(T_INT); \
|
||||||
}
|
}
|
||||||
fmt = (char*)fmt0;
|
CHAR_TYPE* fmt = const_cast<CHAR_TYPE*>(fmt0);
|
||||||
|
CHAR_TYPE* cp;
|
||||||
typetable = stattypetable;
|
typetable = stattypetable;
|
||||||
tablesize = STATIC_ARG_TBL_SIZE;
|
tablesize = STATIC_ARG_TBL_SIZE;
|
||||||
tablemax = 0;
|
tablemax = 0;
|
||||||
nextarg = 1;
|
nextarg = 1;
|
||||||
memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
|
memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
|
||||||
memset(&ps, 0, sizeof(ps));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan the format for conversions (`%' character).
|
* Scan the format for conversions (`%' character).
|
||||||
*/
|
*/
|
||||||
for (;;) {
|
for (;;) {
|
||||||
cp = fmt;
|
for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) continue;
|
||||||
while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
|
if (ch == '\0') goto done;
|
||||||
fmt += n;
|
|
||||||
if (wc == '%') {
|
|
||||||
fmt--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (n < 0) return (-1);
|
|
||||||
if (n == 0) goto done;
|
|
||||||
fmt++; /* skip over '%' */
|
fmt++; /* skip over '%' */
|
||||||
|
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
|
|
@ -277,7 +277,6 @@ static int exponent(CharT* p0, int exp, int fmtch) {
|
||||||
#define MAXINT 0x1000 /* largest integer size (intmax_t) */
|
#define MAXINT 0x1000 /* largest integer size (intmax_t) */
|
||||||
|
|
||||||
int __vfwprintf(FILE* __restrict fp, const wchar_t* __restrict fmt0, __va_list ap) {
|
int __vfwprintf(FILE* __restrict fp, const wchar_t* __restrict fmt0, __va_list ap) {
|
||||||
wchar_t* fmt; /* format string */
|
|
||||||
wchar_t ch; /* character from fmt */
|
wchar_t ch; /* character from fmt */
|
||||||
int n, n2, n3; /* handy integers (short term usage) */
|
int n, n2, n3; /* handy integers (short term usage) */
|
||||||
wchar_t* cp; /* handy char pointer (short term usage) */
|
wchar_t* cp; /* handy char pointer (short term usage) */
|
||||||
|
@ -336,10 +335,12 @@ int __vfwprintf(FILE* __restrict fp, const wchar_t* __restrict fmt0, __va_list a
|
||||||
* below longer.
|
* below longer.
|
||||||
*/
|
*/
|
||||||
#define PADSIZE 16 /* pad chunk size */
|
#define PADSIZE 16 /* pad chunk size */
|
||||||
static wchar_t blanks[PADSIZE] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
|
static CHAR_TYPE blanks[PADSIZE] = {
|
||||||
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };
|
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '
|
||||||
static wchar_t zeroes[PADSIZE] = { '0', '0', '0', '0', '0', '0', '0', '0',
|
};
|
||||||
'0', '0', '0', '0', '0', '0', '0', '0' };
|
static CHAR_TYPE zeroes[PADSIZE] = {
|
||||||
|
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'
|
||||||
|
};
|
||||||
|
|
||||||
static const char xdigs_lower[] = "0123456789abcdef";
|
static const char xdigs_lower[] = "0123456789abcdef";
|
||||||
static const char xdigs_upper[] = "0123456789ABCDEF";
|
static const char xdigs_upper[] = "0123456789ABCDEF";
|
||||||
|
@ -432,7 +433,10 @@ int __vfwprintf(FILE* __restrict fp, const wchar_t* __restrict fmt0, __va_list a
|
||||||
int hold = nextarg; \
|
int hold = nextarg; \
|
||||||
if (argtable == NULL) { \
|
if (argtable == NULL) { \
|
||||||
argtable = statargtable; \
|
argtable = statargtable; \
|
||||||
__find_arguments(fmt0, orgap, &argtable, &argtablesiz); \
|
if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) { \
|
||||||
|
ret = -1; \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
} \
|
} \
|
||||||
nextarg = n2; \
|
nextarg = n2; \
|
||||||
val = GETARG(int); \
|
val = GETARG(int); \
|
||||||
|
@ -451,17 +455,19 @@ int __vfwprintf(FILE* __restrict fp, const wchar_t* __restrict fmt0, __va_list a
|
||||||
((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : (nextarg++, va_arg(ap, type)))
|
((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : (nextarg++, va_arg(ap, type)))
|
||||||
|
|
||||||
_SET_ORIENTATION(fp, 1);
|
_SET_ORIENTATION(fp, 1);
|
||||||
/* sorry, fwprintf(read_only_file, "") returns EOF, not 0 */
|
|
||||||
|
// Writing "" to a read only file returns EOF, not 0.
|
||||||
if (cantwrite(fp)) {
|
if (cantwrite(fp)) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return (EOF);
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* optimise fwprintf(stderr) (and other unbuffered Unix files) */
|
// Optimize writes to stderr and other unbuffered files).
|
||||||
if ((fp->_flags & (__SNBF | __SWR | __SRW)) == (__SNBF | __SWR) && fp->_file >= 0)
|
if ((fp->_flags & (__SNBF | __SWR | __SRW)) == (__SNBF | __SWR) && fp->_file >= 0) {
|
||||||
return (__sbprintf(fp, fmt0, ap));
|
return (__sbprintf(fp, fmt0, ap));
|
||||||
|
}
|
||||||
|
|
||||||
fmt = (wchar_t*)fmt0;
|
CHAR_TYPE* fmt = const_cast<CHAR_TYPE*>(fmt0);
|
||||||
argtable = NULL;
|
argtable = NULL;
|
||||||
nextarg = 1;
|
nextarg = 1;
|
||||||
va_copy(orgap, ap);
|
va_copy(orgap, ap);
|
||||||
|
@ -540,7 +546,10 @@ int __vfwprintf(FILE* __restrict fp, const wchar_t* __restrict fmt0, __va_list a
|
||||||
nextarg = n;
|
nextarg = n;
|
||||||
if (argtable == NULL) {
|
if (argtable == NULL) {
|
||||||
argtable = statargtable;
|
argtable = statargtable;
|
||||||
__find_arguments(fmt0, orgap, &argtable, &argtablesiz);
|
if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) {
|
||||||
|
ret = -1;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
goto rflag;
|
goto rflag;
|
||||||
}
|
}
|
||||||
|
@ -572,7 +581,10 @@ int __vfwprintf(FILE* __restrict fp, const wchar_t* __restrict fmt0, __va_list a
|
||||||
nextarg = n;
|
nextarg = n;
|
||||||
if (argtable == NULL) {
|
if (argtable == NULL) {
|
||||||
argtable = statargtable;
|
argtable = statargtable;
|
||||||
__find_arguments(fmt0, orgap, &argtable, &argtablesiz);
|
if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) {
|
||||||
|
ret = -1;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
goto rflag;
|
goto rflag;
|
||||||
}
|
}
|
||||||
|
@ -1037,12 +1049,10 @@ finish:
|
||||||
* used since we are attempting to make snprintf thread safe, and alloca is
|
* used since we are attempting to make snprintf thread safe, and alloca is
|
||||||
* problematic since we have nested functions..)
|
* problematic since we have nested functions..)
|
||||||
*/
|
*/
|
||||||
static int __find_arguments(const wchar_t* fmt0, va_list ap, union arg** argtable,
|
static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable,
|
||||||
size_t* argtablesiz) {
|
size_t* argtablesiz) {
|
||||||
wchar_t* fmt; /* format string */
|
|
||||||
int ch; /* character from fmt */
|
int ch; /* character from fmt */
|
||||||
int n, n2; /* handy integer (short term usage) */
|
int n, n2; /* handy integer (short term usage) */
|
||||||
wchar_t* cp; /* handy char pointer (short term usage) */
|
|
||||||
int flags; /* flags as above */
|
int flags; /* flags as above */
|
||||||
unsigned char* typetable; /* table of types */
|
unsigned char* typetable; /* table of types */
|
||||||
unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
|
unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
|
||||||
|
@ -1108,7 +1118,8 @@ static int __find_arguments(const wchar_t* fmt0, va_list ap, union arg** argtabl
|
||||||
} else { \
|
} else { \
|
||||||
ADDTYPE(T_INT); \
|
ADDTYPE(T_INT); \
|
||||||
}
|
}
|
||||||
fmt = (wchar_t*)fmt0;
|
CHAR_TYPE* fmt = const_cast<CHAR_TYPE*>(fmt0);
|
||||||
|
CHAR_TYPE* cp;
|
||||||
typetable = stattypetable;
|
typetable = stattypetable;
|
||||||
tablesize = STATIC_ARG_TBL_SIZE;
|
tablesize = STATIC_ARG_TBL_SIZE;
|
||||||
tablemax = 0;
|
tablemax = 0;
|
||||||
|
|
Loading…
Reference in New Issue