Skip to content

Bug #85819 Add AArch64 optimized crc32c implementation #136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed

Bug #85819 Add AArch64 optimized crc32c implementation #136

wants to merge 2 commits into from

Conversation

guyuqi
Copy link

@guyuqi guyuqi commented Apr 6, 2017

ARMv8 defines a set of optional CRC32/CRC32C instructions.
The CRC32 function for AArch64 that uses these instructions will optimize the performance rather than that uses table-based lookup.

I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

Bug #85819: https://bugs.mysql.com/bug.php?id=85819

@akopytov
Copy link

akopytov commented Apr 6, 2017

A similar patch has been contributed in #31, but has never appeared in any released version.

@mysql-oca-bot
Copy link

Hi, thank you for your contribution. Please confirm this code is submitted under the terms of the OCA (Oracle's Contribution Agreement) you have previously signed by cutting and pasting the following text as a comment:
"I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it."
Thanks

ARMv8 defines PMULL crypto instruction. The new patch optimizes crc32c calculate with the instruction when available rather than original linear crc32 instructions.
@guyuqi
Copy link
Author

guyuqi commented Apr 7, 2017

I updated the crc32 optimization code. @akopytov

ARMv8 defines PMULL crypto instruction. The new patch optimizes crc32c calculate with the PMULL instruction when available rather than original linear crc32 instructions.

The result of benchmark:
Platform \ Case (millisecond) | Software CRC | AArch64 CRC Intrinsics | AArch64 Crypto instruction
AMD seattle (Softiron) |1101.783 |200.535 |114.509
Cavium ThunderX |1504.497 |479.690 |286.274
Hisilicon Taishan( Huawei) |1035.202 |232.984 |115.580

It shows that the performance for CRC32 of innodb on AArch64 is better than linear crc32 instruction.

@guyuqi
Copy link
Author

guyuqi commented Apr 7, 2017

I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

@mysql-oca-bot
Copy link

Hi, thank you for your contribution. Your code has been assigned to an internal queue. Please follow
bug http://bugs.mysql.com/bug.php?id=85819 for updates.
Thanks

@houjibofa
Copy link

houjibofa commented Apr 17, 2018

I test the patch in the Huawei Taishan 2208 board, but it compile failed. The error information is:

error: #error You must enable AdvancedSIMD instructions to use arm_neon.h

the CPU information is

processor : 63
BogoMIPS : 100.00
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part : 0xd08
CPU revision : 2

Whether lacking some or not?

Thanks

@longlbj
Copy link

longlbj commented Oct 11, 2019

When running the mtr case: innodb.doublewrite, program terminated with signal SIGSEGV, Segmentation fault.
#1 0x00000000018d1f78 in my_write_core (sig=11) at ../mysys/stacktrace.c:249
#2 0x0000000000f43e14 in handle_fatal_signal (sig=11) at ../sql/signal_handler.cc:220
#3
#4 0x0000000000000000 in ?? ()
#5 0x0000000001a2e3d0 in page_zip_calc_checksum (data=0xffffb7f6b400, size=1024, algo=SRV_CHECKSUM_ALGORITHM_CRC32, use_legacy_big_endian=true) at ../storage/innobase/page/page0zip.cc:4957

dbussink added a commit to planetscale/mysql-server that referenced this pull request Mar 6, 2024
The my_instr_mb function makes the incorrect assumption in multiple
places that byte lengths for the input strings can be used to short cut
certain decisions. In the case of multibyte character sets and
collations, this can't be done though since characters with a different
byte length can be considered equal under collation rules.

Take for example 'a' and 'Å' which are considered equal under the
default MySQL 8 collation utf8mb4_0900_ai_ci:

mysql> select 'a' = 'Å';
+-------------+
| 'a' = 'Å'   |
+-------------+
|           1 |
+-------------+
1 row in set (0.00 sec)

The character 'a' is though encoded with 1 byte, but 'Å' is encoded with
3 bytes. When using LOCATE, it should also find the character:

mysql> select locate('a', 'Å');
+--------------------+
| locate('a', 'Å')   |
+--------------------+
|                  0 |
+--------------------+
1 row in set (0.00 sec)

It shows here that it's wrong, and it doesn't consider the character a
substring of the other character, which mismatches the behavior seen
when checking equality above.

This is due to a number of bugs. First of all, there is this check at
the beginning:

if (s_length <= b_length) {

To be explicit, both length variables here are byte lengths, not
character lengths of the inputs. When this check does not match and the
byte length of needle is longer than the haystack, the assumption is
made that no result can be found. This is wrong, because in case here of
a needle of 'Å' it will have 3 bytes, but the haystack of 'a' has 1
byte. We still need to search through with the proper collation
settings. Therefore the change here removes this check as it's an
incorrect optimization trying to short circuit.

There's another attempt at optimization here to reduce the maximum
string length searched:

end = b + b_length - s_length + 1;

This is also not correct because of the same reason. We can't assume
byte lengths match character lengths, so this is changed to:

end = b + b_length

to ensure that the whole haystack string is searched.

Lastly, there's another bug. The call to strnncoll again assumes that
you can truncate the haystack to the byte length. This goes wrong if the
needle is 'a' and the haystack is 'Å'. In that case, the haystack string
of 'Å' is 3 bytes long and will be cut off at 1 byte. This results in an
invalid UTF-8 input and no match on the search.

Instead, strnncoll has a prefix option, so we use that and pass in the
full string lenghts so that a proper search for a prefix is made.

The higher level Item_func_locate function also has a bug where
incorrectly byte length is used. The following is incorrect:

return start + 1;

As start here is just updated from the character position to the byte
position. Instead, we need to use start0 here to return the correct
offset.

These changes resolve the given bugs around multibyte characters and
substring searching.

Signed-off-by: Dirkjan Bussink <[email protected]>
dbussink added a commit to planetscale/mysql-server that referenced this pull request May 21, 2024
The my_instr_mb function makes the incorrect assumption in multiple
places that byte lengths for the input strings can be used to short cut
certain decisions. In the case of multibyte character sets and
collations, this can't be done though since characters with a different
byte length can be considered equal under collation rules.

Take for example 'a' and 'Å' which are considered equal under the
default MySQL 8 collation utf8mb4_0900_ai_ci:

mysql> select 'a' = 'Å';
+-------------+
| 'a' = 'Å'   |
+-------------+
|           1 |
+-------------+
1 row in set (0.00 sec)

The character 'a' is though encoded with 1 byte, but 'Å' is encoded with
3 bytes. When using LOCATE, it should also find the character:

mysql> select locate('a', 'Å');
+--------------------+
| locate('a', 'Å')   |
+--------------------+
|                  0 |
+--------------------+
1 row in set (0.00 sec)

It shows here that it's wrong, and it doesn't consider the character a
substring of the other character, which mismatches the behavior seen
when checking equality above.

This is due to a number of bugs. First of all, there is this check at
the beginning:

if (s_length <= b_length) {

To be explicit, both length variables here are byte lengths, not
character lengths of the inputs. When this check does not match and the
byte length of needle is longer than the haystack, the assumption is
made that no result can be found. This is wrong, because in case here of
a needle of 'Å' it will have 3 bytes, but the haystack of 'a' has 1
byte. We still need to search through with the proper collation
settings. Therefore the change here removes this check as it's an
incorrect optimization trying to short circuit.

There's another attempt at optimization here to reduce the maximum
string length searched:

end = b + b_length - s_length + 1;

This is also not correct because of the same reason. We can't assume
byte lengths match character lengths, so this is changed to:

end = b + b_length

to ensure that the whole haystack string is searched.

Lastly, there's another bug. The call to strnncoll again assumes that
you can truncate the haystack to the byte length. This goes wrong if the
needle is 'a' and the haystack is 'Å'. In that case, the haystack string
of 'Å' is 3 bytes long and will be cut off at 1 byte. This results in an
invalid UTF-8 input and no match on the search.

Instead, strnncoll has a prefix option, so we use that and pass in the
full string lenghts so that a proper search for a prefix is made.

The higher level Item_func_locate function also has a bug where
incorrectly byte length is used. The following is incorrect:

return start + 1;

As start here is just updated from the character position to the byte
position. Instead, we need to use start0 here to return the correct
offset.

These changes resolve the given bugs around multibyte characters and
substring searching.

Signed-off-by: Dirkjan Bussink <[email protected]>
dbussink added a commit to planetscale/mysql-server that referenced this pull request May 21, 2024
The my_instr_mb function makes the incorrect assumption in multiple
places that byte lengths for the input strings can be used to short cut
certain decisions. In the case of multibyte character sets and
collations, this can't be done though since characters with a different
byte length can be considered equal under collation rules.

Take for example 'a' and 'Å' which are considered equal under the
default MySQL 8 collation utf8mb4_0900_ai_ci:

mysql> select 'a' = 'Å';
+-------------+
| 'a' = 'Å'   |
+-------------+
|           1 |
+-------------+
1 row in set (0.00 sec)

The character 'a' is though encoded with 1 byte, but 'Å' is encoded with
3 bytes. When using LOCATE, it should also find the character:

mysql> select locate('a', 'Å');
+--------------------+
| locate('a', 'Å')   |
+--------------------+
|                  0 |
+--------------------+
1 row in set (0.00 sec)

It shows here that it's wrong, and it doesn't consider the character a
substring of the other character, which mismatches the behavior seen
when checking equality above.

This is due to a number of bugs. First of all, there is this check at
the beginning:

if (s_length <= b_length) {

To be explicit, both length variables here are byte lengths, not
character lengths of the inputs. When this check does not match and the
byte length of needle is longer than the haystack, the assumption is
made that no result can be found. This is wrong, because in case here of
a needle of 'Å' it will have 3 bytes, but the haystack of 'a' has 1
byte. We still need to search through with the proper collation
settings. Therefore the change here removes this check as it's an
incorrect optimization trying to short circuit.

There's another attempt at optimization here to reduce the maximum
string length searched:

end = b + b_length - s_length + 1;

This is also not correct because of the same reason. We can't assume
byte lengths match character lengths, so this is changed to:

end = b + b_length

to ensure that the whole haystack string is searched.

Lastly, there's another bug. The call to strnncoll again assumes that
you can truncate the haystack to the byte length. This goes wrong if the
needle is 'a' and the haystack is 'Å'. In that case, the haystack string
of 'Å' is 3 bytes long and will be cut off at 1 byte. This results in an
invalid UTF-8 input and no match on the search.

Instead, strnncoll has a prefix option, so we use that and pass in the
full string lenghts so that a proper search for a prefix is made.

The higher level Item_func_locate function also has a bug where
incorrectly byte length is used. The following is incorrect:

return start + 1;

As start here is just updated from the character position to the byte
position. Instead, we need to use start0 here to return the correct
offset.

These changes resolve the given bugs around multibyte characters and
substring searching.

Signed-off-by: Dirkjan Bussink <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants