Bug #14637 trim trailing spaces processes data only byte wise

Submitted: 4 Nov 2005 12:51 Modified: 6 Mar 2010 19:11
Reporter: Gunnar von Boehn Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S5 (Performance)
Version:5.0-BK OS:Any (any)
Assigned to: Georgi Kodinov CPU Architecture:Any

[4 Nov 2005 12:51] Gunnar von Boehn
Description:
In the file strings/ctype-simple.c
are two functions which trim blank spaces from the end of a string.
my_hash_sort_simple() and my_lengthsp_8bit().

Both functions parse the string byte wise and are quite slow for longer strings.

suggested improvement see below

How to repeat:
na

Suggested fix:
Changing the function from parsing the string 8bit wise to work on 32bit wise
would make sense for architectures beeing able to work in unaligned 32bit words.

We would sacrifice a little performance for strings which have zero or only one blank space
but we would gain a very good improvement for strings with more blank spaces.

So instead doing something like this:
int my_hash( char *start, int len){
const char *end= start + len;
while (end > start && end[-1] == ' ')
          end--;
return end;
}

We could do:
int my_hash_32bit( char *start, int len){
const char *end= start + len;
const char *start2= start + (long)(len & 3);
while (end > (unsigned long*)start2 ){
  if( ((unsigned long*)end)[-1] != 0x20202020) break;
  end-=4;
}
while (end > (unsigned char*)start ){
  if( ((unsigned char*)end)[-1] != ' ') break;
  end--;
}
return end;
}

Below is a POWER/PC assembler version of the above function.
please note: the asm function does not test for strings for length=0.
I assume that this case will never appear in MySQL.
Would be good if someone could verify this!

The below asm function beats the current C function for nearly every case,
its only slower for the case of exactly one blank space.

// ##################################################
// find length of string without trailing blankspaces
//
// r3 = ptr to string
// r4 = length of string

asm(
".text                          \n"
".align  4                      \n"
".globl  trim_blankspace_32bit  \n"
"                               \n"
"trim_blankspace_32bit:         \n"
"   mr    r9,r3                 \n"
"   add   r3,r3,r4              \n"
"   lbz   r6,-1(r3)             \n"     // preload end of string
"   andi. r0,r4,3               \n"     //
"   add   r8,r9,r0              \n"
"   lis   r5,0x2020             \n"
"   ori   r5,r5,0x2020          \n"
"   cmpwi cr0,r6,0x20           \n"     // quick exit for 0 blank spaces
"   bnelr+ cr0                  \n"     //
".align  4                      \n"
".loop32bit:                    \n"
"   cmplw cr1,r3,r8             \n"
"   ble-  cr1,.test8bit         \n"
"   lwzu  r4,-4(r3)             \n"
"   cmpw  cr0,r4,r5             \n"
"   bne-  cr0,.start8bit        \n"

"   cmplw cr1,r3,r8             \n"
"   ble-  cr1,.test8bit         \n"
"   lwzu  r4,-4(r3)             \n"
"   cmpw  cr0,r4,r5             \n"
"   beq+  cr0,.loop32bit        \n"

".start8bit:                    \n"     // 32bit test did not match
"   addi  r3,r3,4               \n"     // retest the last 4 bytes
".test8bit:                     \n"
                                        // loop unrolled
"   cmplw  cr1,r3,r9            \n"     // max 3 bytes to test
"   blelr+ cr1                  \n"
"   lbz    r4,-1(r3)            \n"
"   cmpwi  cr0,r4,0x20          \n"
"   bnelr  cr0                  \n"
"   subi   r3,r3,1              \n"
"   cmplw  cr1,r3,r9            \n"
"   blelr+ cr1                  \n"
"   lbz    r4,-1(r3)            \n"
"   cmpwi  cr0,r4,0x20          \n"
"   bnelr  cr0                  \n"
"   subi   r3,r3,1              \n"
"   cmplw  cr1,r3,r9            \n"
"   blelr+ cr1                  \n"
"   lbz    r4,-1(r3)            \n"
"   cmpwi  cr0,r4,0x20          \n"
"   bnelr  cr0                  \n"
"   subi   r3,r3,1              \n"
"   blr                         \n"
);

Cheers
Gunnar
[4 Nov 2005 13:21] Valeriy Kravchuk
In today's 5.0-BK sources (ChangeSet@1.1957.1.18, 2005-11-03 20:29:21+02:00, jani@ua141d10.elisa.omakaista.fi) one may see the following:

void my_hash_sort_simple(CHARSET_INFO *cs,
                         const uchar *key, uint len,
                         ulong *nr1, ulong *nr2)
{
  register uchar *sort_order=cs->sort_order;
  const uchar *end= key + len;

  /*
    Remove end space. We have to do this to be able to compare
    'A ' and 'A' as identical
  */
  while (end > key && end[-1] == ' ')
    end--;
...

So, yes, it is byte after byte processing, and it may be optimized.
[6 Feb 2008 16:46] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/41796

ChangeSet@1.2799, 2008-02-06 18:45:46+02:00, gkodinov@magare.gmz +5 -0
  Bug #14637: trim trailing spaces processes data only byte wise
   Use and int * where possible to scan for trailing space in a
   string instead of always iterating char-by-char.
[7 Feb 2008 10:26] Georgi Kodinov
sample benchmark file

Attachment: test.test (, text), 1.11 KiB.

[7 Feb 2008 10:27] Georgi Kodinov
Using the attached benchmark file on a 32 bit Intel Core 2 Duo CPU I've got 43485 ms run with the fix compared to 44373 without it.
[13 Feb 2008 14:53] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/42219

ChangeSet@1.2799, 2008-02-13 16:53:24+02:00, gkodinov@magare.gmz +8 -0
  Bug #14637: trim trailing spaces processes data only byte wise
   Use and int * where possible to scan for trailing space in a
   string instead of always iterating char-by-char.
   Using the attached benchmark file on a 32 bit Intel Core 2 
   Duo CPU I've got 43485 ms run with the fix compared to 44373 
   without it.
[16 Feb 2008 9:08] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/42418

ChangeSet@1.2799, 2008-02-16 11:08:10+02:00, gkodinov@magare.gmz +5 -0
  Bug #14637: trim trailing spaces processes data only byte wise
   Use and int * where possible to scan for trailing space in a
   string instead of always iterating char-by-char.
   Using the attached benchmark file on a 32 bit Intel Core 2 
   Duo CPU I've got 43485 ms run with the fix compared to 44373 
   without it.
[13 Mar 2008 19:27] Bugs System
Pushed into 6.0.5-alpha
[15 Mar 2008 19:26] Jon Stephens
Documented in the 6.0.5 changelog as follows:

        The performance of internal functions that trim multiple spaces from
        strings when comparing them has been improved.
[11 Nov 2009 16:04] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/90112
[11 Nov 2009 16:05] Magne Mæhre
Backported to 5.6.0 (next-mr-runtime)
(6.0-codebase revid: 2476.1362.1)
[20 Nov 2009 12:54] Bugs System
Pushed into 5.6.0-beta (revid:davi.arnaut@sun.com-20091119234808-xbjpkwaxjt5x5c0b) (version source revid:davi.arnaut@sun.com-20091119234808-xbjpkwaxjt5x5c0b) (merge vers: 5.6.0-beta) (pib:13)
[20 Nov 2009 12:57] Bugs System
Pushed into 6.0.14-alpha (revid:kostja@sun.com-20091120124947-yi6h2jbgw0kbciwm) (version source revid:kostja@sun.com-20091119222407-5a7cjlhw06trtxnf) (merge vers: 6.0.14-alpha) (pib:13)
[20 Nov 2009 15:10] Paul DuBois
Noted in 5.6.0 changelog.

Already fixed in earlier 6.0.x release.
[6 Mar 2010 11:02] Bugs System
Pushed into 5.5.3-m3 (revid:alik@sun.com-20100306103849-hha31z2enhh7jwt3) (version source revid:vvaintroub@mysql.com-20091120154107-6awpq04plug2xlri) (merge vers: 5.6.0-beta) (pib:16)
[6 Mar 2010 19:11] Paul DuBois
Moved 5.6.0 changelog entry to 5.5.3.

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.106 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.