Commit 48ab5a49 authored by Alexander Barkov's avatar Alexander Barkov

Part2: MDEV-23568 Improve performance of my_{time|date|datetime}_to_str()

As an additional improvement, let's store string representations of
the numbers using an array uint16[256] instead of char[512].
This allows to use int2store(), which copies two bytes at a time on x86,
instead of copying the two bytes with digits one-by-one.

This change gives an additional 7% to 26% query time reduce for:
    SELECT BENCHMARK(10*1000*1000,CONCAT(TIME'10:20:30'));
    SELECT BENCHMARK(10*1000*1000,CONCAT(TIME'10:20:30.123456'));
    SELECT BENCHMARK(10*1000*1000,CONCAT(DATE'2001-01-01'));
    SELECT BENCHMARK(10*1000*1000,CONCAT(TIMESTAMP'2001-01-01 10:20:30'));
    SELECT BENCHMARK(10*1000*1000,CONCAT(TIMESTAMP'2001-01-01 10:20:30.123456'));

The total time reduce (part1 + part2) is now between 15% to 38%
for these queries.
parent 0af6e525
...@@ -1471,55 +1471,68 @@ void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type) ...@@ -1471,55 +1471,68 @@ void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type)
SELECT BENCHMARK(10*1000*1000,CONCAT(TIMESTAMP'2001-01-01 10:20:30.123456')); SELECT BENCHMARK(10*1000*1000,CONCAT(TIMESTAMP'2001-01-01 10:20:30.123456'));
(depending on the exact data type and fractional precision). (depending on the exact data type and fractional precision).
The array has extra elements for uint8 values 100..255. The array has extra elements for values 100..255.
This is done for safety. If the caller passes a value This is done for safety. If the caller passes a value
outside of the expected range 0..99, it will be printed as "XX". outside of the expected range 0..99, the value will be printed as "XX".
*/
Part2:
As an additional improvement over "class TwoDigitWriter", we store
the string representations of the numbers in an array uint16[256]
instead of char[512]. This allows to copy data using int2store(),
which copies two bytes at a time on x86 and gives an additional
7% to 26% time reduce over copying the two bytes separately.
The total time reduce is 15% to 38% on the above queries.
static const char two_digit_numbers[512+1]= The bytes in the following array are swapped:
e.g. 0x3130 in two_digit_numbers[1] means the following:
- 0x31 is '1' (the left byte, the right digit)
- 0x30 is '0' (the right byte, the left digit)
int2store() puts the lower byte first, so the output string becomes '01'.
*/
static const uint16 two_digit_numbers[256]=
{ {
/* 0..99 */ /* 0..99 */
"00010203040506070809" 0x3030,0x3130,0x3230,0x3330,0x3430,0x3530,0x3630,0x3730,0x3830,0x3930,
"10111213141516171819" 0x3031,0x3131,0x3231,0x3331,0x3431,0x3531,0x3631,0x3731,0x3831,0x3931,
"20212223242526272829" 0x3032,0x3132,0x3232,0x3332,0x3432,0x3532,0x3632,0x3732,0x3832,0x3932,
"30313233343536373839" 0x3033,0x3133,0x3233,0x3333,0x3433,0x3533,0x3633,0x3733,0x3833,0x3933,
"40414243444546474849" 0x3034,0x3134,0x3234,0x3334,0x3434,0x3534,0x3634,0x3734,0x3834,0x3934,
"50515253545556575859" 0x3035,0x3135,0x3235,0x3335,0x3435,0x3535,0x3635,0x3735,0x3835,0x3935,
"60616263646566676869" 0x3036,0x3136,0x3236,0x3336,0x3436,0x3536,0x3636,0x3736,0x3836,0x3936,
"70717273747576777879" 0x3037,0x3137,0x3237,0x3337,0x3437,0x3537,0x3637,0x3737,0x3837,0x3937,
"80818283848586878889" 0x3038,0x3138,0x3238,0x3338,0x3438,0x3538,0x3638,0x3738,0x3838,0x3938,
"90919293949596979899" 0x3039,0x3139,0x3239,0x3339,0x3439,0x3539,0x3639,0x3739,0x3839,0x3939,
/* 100..199 - safety */ /* 100..199 - safety */
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
/* 200..255 - safety */ /* 200..255 - safety */
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
"XXXXXXXXXXXX" 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,
}; };
static inline char* fmt_number2(uint8 val, char *out) static inline char* fmt_number2(uint8 val, char *out)
{ {
const char *src= two_digit_numbers + val * 2; int2store(out, two_digit_numbers[val]);
*out++= *src++; return out + 2;
*out++= *src++;
return out;
} }
/* /*
We tried the same trick with an array of 16384 zerofill 4-digit numbers, We tried the same trick with a char array of 16384 zerofill 4-digit numbers,
with 10000 elements with numbers 0000..9999, and a tail filled with "XXXX". with 10000 elements with numbers 0000..9999, and a tail filled with "XXXX".
Benchmark results for a RelWithDebInfo build: Benchmark results for a RelWithDebInfo build:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment