MySQL编译选项 -fno-strict-aliasing随手记

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介:

最近发布的MySQL8.0.2版本中,将gcc的编译选项从--fno-strict-aliasing移除,也就是说打开strict aliasing, 根据worklog #10344 的描述,在单线程的性能测试中,有最多%4的性能提升,还是相当可观的。这个flag在我们内部编译版本中也是一直打开的,但一直不知甚解。本文是网上搜索文档和自己试验的小结。

首先strict aliasing是个什么鬼? --fno-strict-aliasing对应的是--f-strict-aliasing,GCC文档的解释如下:

Allow the compiler to assume the strictest aliasing rules applicable to the language being compiled. For C (and C++), this activates optimizations based on the type of expressions. In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same. For example, an unsigned int can alias an int, but not a void* or a double. A character type may alias any other type.

Stackoverflow上关于strict aliasing规则的问题

当使用strict aliasing时, 编译器会认为在不同类型之间的转换不会发生,因此执行更激进的编译优化,例如reorder执行顺序。

Strcit aliasing只能隐式的开启或者显式的禁止掉。在-o2或更高的编译级别上会被隐式开启。

这里举个简单的例子,参考网络 上这篇文章

$cat x.c
#include <stdio.h>
#include <stdint.h>

int main()
{
        int a = 0x12345678;

        uint16_t* const sp = (uint16_t*)&a;
        uint16_t hi = sp[0];
        uint16_t lo = sp[1];

        sp[1] = hi;
        sp[0] = lo;

        printf("%x\n", a);

        return 0;
}

函数的功能很简单,对一个数字的高低位进行交换

gcc版本

$gcc --version
gcc (GCC) 4.4.6 20110731 (Red Hat 4.4.6-3)

执行strict aliasing (O2及以上默认打开)

$gcc -O2  x.c

$./a.out
12345678

非strict aliasing (显式指定-fno-strict-aliasing)

$gcc -O2 -fno-strict-aliasing x.c

$./a.out
56781234

不同的gcc flag,两次的执行结果居然完全不相同,只有第二次才实现了预期功能。因为默认情况下不报warning,我们把告警打开看看:

$gcc -O2 -Wstrict-aliasing x.c
x.c: In function ‘main’:
x.c:13: warning: dereferencing pointer ‘sp’ does break strict-aliasing rules
x.c:9: warning: dereferencing pointer ‘sp’ does break strict-aliasing rules
x.c:8: note: initialized from here
x.c:10: warning: dereferencing pointer ‘({anonymous})’ does break strict-aliasing rules
x.c:10: note: initialized from here
x.c:12: warning: dereferencing pointer ‘({anonymous})’ does break strict-aliasing rules
x.c:12: note: initialized from her

果然在使用strict aliasing时,因为破坏了严格aliasing的规则大量报警,因此如果我们要使用strict aliasing,一定要打开报警,并重视每个warning。

回到刚才的问题,为什么strict aliasing会输出最原始的数据,而不是修改后的数据呢 ? 看起来就好像后面的修改全部被忽略掉了一样。 我们来看看编译后的代码。可以看到两个汇编代码完全不相同。编译器认为代码里不可能出现不规范的类型转换,所以在错误的案例里,a的未被修改的值被直接抛给了printf函数

正确的 (gcc -O2 -fno-strict-aliasing x.c)

(gdb) disassemble main
Dump of assembler code for function main:
   0x00000000004004d0 <+0>:     sub    $0x18,%rsp
   0x00000000004004d4 <+4>:     mov    $0x4005f8,%edi
   0x00000000004004d9 <+9>:     xor    %eax,%eax
   0x00000000004004db <+11>:    movw   $0x5678,0xe(%rsp)
   0x00000000004004e2 <+18>:    movw   $0x1234,0xc(%rsp)
   0x00000000004004e9 <+25>:    mov    0xc(%rsp),%esi
   0x00000000004004ed <+29>:    callq  0x4003b8 <printf@plt>
   0x00000000004004f2 <+34>:    xor    %eax,%eax
   0x00000000004004f4 <+36>:    add    $0x18,%rsp
   0x00000000004004f8 <+40>:    retq
End of assembler dump.

错误的 (gcc -O2 -fstrict-aliasing x.c)

(gdb) disassemble main
Dump of assembler code for function main:
   0x00000000004004d0 <+0>:     sub    $0x18,%rsp
   0x00000000004004d4 <+4>:     mov    $0x12345678,%esi
   0x00000000004004d9 <+9>:     mov    $0x4005f8,%edi
   0x00000000004004de <+14>:    xor    %eax,%eax
   0x00000000004004e0 <+16>:    movw   $0x5678,0xe(%rsp)
   0x00000000004004e7 <+23>:    movw   $0x1234,0xc(%rsp)
   0x00000000004004ee <+30>:    callq  0x4003b8 <printf@plt>
   0x00000000004004f3 <+35>:    xor    %eax,%eax
   0x00000000004004f5 <+37>:    add    $0x18,%rsp
   0x00000000004004f9 <+41>:    retq
End of assembler dump.

但是如果我换成高版本的gcc,例如4.8版本,两种编译方式都没有问题,甚至加上-Wstrict-aliasing连报警都没有。只有加上-Wstrict-aliasing=1才报warning

$/opt/rh/devtoolset-2/root/usr/bin/gcc --version
gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-15)

$/opt/rh/devtoolset-2/root/usr/bin/gcc -O2 -fno-strict-aliasing x.c

$./a.out
56781234

/opt/rh/devtoolset-2/root/usr/bin/gcc -O2 -fstrict-aliasing x.c

$./a.out
56781234

$/opt/rh/devtoolset-2/root/usr/bin/gcc -O2 -fstrict-aliasing -Wstrict-aliasing=1 x.c
x.c: In function ‘main’:
x.c:9:2: warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
  uint16_t* const sp = (uint16_t*)&a;

网上搜了一下,Stackoverflow上有一些类似的问题 12。 我理解这应该是gcc编译器的高版本对类型转换规则的识别可能做的更加好,细节不太了解,如有看到这篇文章的朋友,求帮忙修正 :)

!!!无论如何, 如果你需要打开strict aliasing, 一定要打开Wstrict-aliasing,消除代码warning。 同时在代码上也要尽量减少这种不同类型的转换。

在MySQL移除-fno-strict-aliasing后, 也看到了一些担忧,因为mysql的codebase毕竟已经相当古老了, 而当前并没有一些静态或动态的分析工具能够找到所有违反strict aliasing规则的地方。可能存在潜在的风险。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7月前
|
关系型数据库 MySQL PHP
【Bug解决】Thinkphp5 PDO::__construct(): MySQL server has gone away解决办法
【Bug解决】Thinkphp5 PDO::__construct(): MySQL server has gone away解决办法
|
8月前
|
SQL 关系型数据库 MySQL
MySql 常用插件
MySql 常用插件
44 0
|
9月前
|
关系型数据库 MySQL 网络安全
记一次mysql 5.7.34编译过程错误
记一次mysql 5.7.34编译过程错误
|
NoSQL 关系型数据库 MySQL
MYSQL5的my.ini文件内容(最精简,带注释)
MYSQL5的my.ini文件内容(最精简,带注释)
229 0
|
关系型数据库 MySQL 数据库
【mysql】常见问题解决方法
【mysql】常见问题解决方法
167 0
【mysql】常见问题解决方法
|
关系型数据库 C++ iOS开发
【从入门到放弃-MySQL】CLion调试MySQL8.0源码
前言 想对的MySQL底层实现做一些了解,奈何没有用过C++不知道怎么调试一个大型项目,一日和大神交流时大神扔给我了一份《XCode调试MySQL8秘籍》。于是在几经波折(主要是因为菜)之后终于打开了MySQL的调试大门。
3168 0
|
关系型数据库 MySQL
mysql编译方式安装
1、cmake包安装 上传cmake-2.8.8.tar.gz到opt下,解压tar xf cmake-2.8.8.tar.gz。 执行./configure,报错如下:Error when bootstrapping CMake: Cannot find appropriate C++ compiler on this system. 这是由于最小化安装centos后,没有安装cc编译器,因此yum install gcc、yum install gcc-c++ 再次执行./configure成功。
1215 0
|
关系型数据库 MySQL

相关产品

  • 云数据库 RDS MySQL 版