作者:卢文双 资深数据库内核研发
序言:
以前对 MySQL 测试框架 MTR 的使用,主要集中于 SQL 正确性验证。近期由于工作需要,深入了解了 MTR 的方方面面,发现 MTR 的能力不仅限于此,还支持单元测试、压力测试、代码覆盖率测试、内存错误检测、线程竞争与死锁等功能,因此,本着分享的精神,将其总结成一个系列。
主要内容如下:
- 入门篇:工作机制、编译安装、参数、指令示例、推荐用法、添加 case、常见问题、异常调试
- 进阶篇:高阶用法,包括单元测试、压力测试、代码覆盖率测试、内存错误检测、线程竞争与死锁
- 源码篇:分析 MTR 的源码
- 语法篇:单元测试、压力测试、mysqltest 语法、异常调试
由于个人水平有限,所述难免有错误之处,望雅正。
本文是第二篇进阶篇。
本文首发于 2023-05-01 21:03:44
MTR 系列基于 MySQL 8.0.29 版本(编译情况也在 8.0.32 版本验证过),且主要在 Ubuntu 22.04 X86_64 验证(部分指令也在 Ubuntu 20.04 X86_64、Ubuntu 22.04 ARM64、MacOS M1 做了验证),如有例外,会特别说明。
前言
上一篇文章《MySQL 测试框架 MTR 系列教程(一):入门篇》介绍了 mtr 的原理、目录结构、参数及常见用法,侧重于最常见的 SQL 正确性验证,但 mtr 能做更多的事情,比如 内存错误、线程竞争、代码覆盖率、压力测试等,本文主要介绍这些内容,涉及的相关工具如下:
- valgrind :用于内存调试、内存泄漏检测以及性能分析。
- Sanitizier :谷歌发起的开源工具集。
- ASAN/AddressSanitizier :检查内存地址相关问题,包括内存泄漏、释放后使用、重复释放、堆溢出、栈溢出等等问题。
- LSAN/LeakSanitizer :检查内存泄漏问题。它是集成在 Address Sanitizer 中的一个相对独立的工具,它工作在检查过程的最后阶段。
- MSAN/MemorySanitizer : 检查使用未初始化内存的问题。
- TSAN/ThreadSanitizer : 检查线程数据竞争和死锁问题。
- UBSAN/UndefinedBehaviorSanitizer : 检测未定义行为(使用空指针、有符号整数溢出等)。
- gcov : 代码覆盖率测试。
- gprof : 性能分析工具。
- 单元测试
- 压力测试
本文将逐一介绍对各个工具的支持情况。
补充:
MariaDB 已经很好的支持了以上工具集:
Compile and Using MariaDB with Sanitizers (ASAN, UBSAN, TSAN, MSAN) – MariaDB Knowledge Base
Compiling MariaDB for Debugging – MariaDB Knowledge Base (支持 valgrind)
MySQL 编译选项
首先说明一下与本文相关的 MySQL 编译选项:
-
-DCMAKE_BUILD_TYPE=type
The type of build to produce:
-
RelWithDebInfo
: default value。Enable optimizations and generate debugging information. This is the default MySQL build type. -
Release
: Enable optimizations but omit debugging information to reduce the build size. This build type was added in MySQL 8.0.13 (MySQL 5.7 is not supported). -
Debug
: Disable optimizations and generate debugging information. This build type is also used if the WITH_DEBUG option is enabled. That is, -DWITH_DEBUG=1 has the same effect as -DCMAKE_BUILD_TYPE=Debug.
-
-
-DWITH_DEBUG=bool
Whether to include debugging support. The default is
OFF
. -
-DWITH_ASAN=bool
Whether to enable the AddressSanitizer, for compilers that support it. The default is off.
-
-DWITH_ASAN_SCOPE=bool
Whether to enable the AddressSanitizer
-fsanitize-address-use-after-scope
Clang flag for use-after-scope detection. The default is off. To use this option,-DWITH_ASAN
must also be enabled. -
-DWITH_LSAN=bool
Whether to run LeakSanitizer, without AddressSanitizer. The default is
OFF
.This option was added in MySQL 8.0.16.
-
-DWITH_MSAN=bool
Whether to enable MemorySanitizer, for compilers that support it. The default is off.
For this option to have an effect if enabled, all libraries linked to MySQL must also have been compiled with the option enabled.
-
-DWITH_TSAN=bool
Whether to enable the ThreadSanitizer, for compilers that support it. The default is off.
-
-DWITH_UBSAN=bool
Whether to enable the Undefined Behavior Sanitizer, for compilers that support it. The default is off.
-
-DWITH_UNIT_TESTS={ON|OFF}
If enabled, compile MySQL with unit tests. The default is ON unless the server is not being compiled.
-
-DWITH_VALGRIND=bool
Whether to compile in the Valgrind header files, which exposes the Valgrind API to MySQL code. The default is
OFF
.To generate a Valgrind-aware debug build, -DWITH_VALGRIND=1 normally is combined with -DWITH_DEBUG=1. See Building Debug Configurations.
-
-DENABLE_GCOV=bool
Whether to include
gcov
support (Linux only). -
-DENABLE_GPROF=bool
Whether to enable
gprof
(optimized Linux builds only). The default isOFF
. -
-DWITH_TEST_TRACE_PLUGIN=bool
Whether to build the test protocol trace client plugin (see Using the Test Protocol Trace Plugin). By default, this option is disabled. Enabling this option has no effect unless the WITH_CLIENT_PROTOCOL_TRACING option is enabled. If MySQL is configured with both options enabled, the
libmysqlclient
client library is built with the test protocol trace plugin built in, and all the standard MySQL clients load the plugin. However, even when the test plugin is enabled, it has no effect by default. Control over the plugin is afforded using environment variables; see Using the Test Protocol Trace Plugin.Note
Do not enable the WITH_TEST_TRACE_PLUGIN option if you want to use your own protocol trace plugins because only one such plugin can be loaded at a time and an error occurs for attempts to load a second one. If you have already built MySQL with the test protocol trace plugin enabled to see how it works, you must rebuild MySQL without it before you can use your own plugins.
For information about writing trace plugins, see Writing Protocol Trace Plugins.
-
-DWITH_CLIENT_PROTOCOL_TRACING=bool
Whether to build the client-side protocol tracing framework into the client library. By default, this option is enabled.
For information about writing protocol trace client plugins, see Writing Protocol Trace Plugins.
See also the WITH_TEST_TRACE_PLUGIN option.
-
-DWITH_KEYRING_TEST=bool
Whether to build the test program that accompanies the
keyring_file
plugin. The default isOFF
. Test file source code is located in theplugin/keyring/keyring-test
directory. -
-DWITH_NDB_TEST={ON|OFF}
If enabled, include a set of NDB API test programs. The default is OFF.
详见:MySQL :: MySQL 8.0 Reference Manual :: 2.8.7 MySQL Source-Configuration Options
以下是各组件或测试类型的详细介绍。
valgrind
简介
valgrind 是一个工具集,主要集成了:
- memcheck :内存错误检测器。
- cachegrind :缓存和分支预测分析器。
- callgrind :可生成缓存分析器的调用图。
- helgrind :线程错误检测器。
- DRD :也是线程错误检测器。
- massif :堆分析器,它可以帮助程序使用更少的内存。
- DHAT :一种不同类型的堆分析器。使用它可以了解块寿命,块利用率和布局效率低下的问题。
选项
mtr 提供的 valgrind 选项如下:
Options for valgrind
callgrind Instruct valgrind to use callgrind.
helgrind Instruct valgrind to use helgrind.
valgrind Run the "mysqltest" and "mysqld" executables using
valgrind with default options.
valgrind-all Synonym for --valgrind.
valgrind-clients Run clients started by .test files with valgrind.
valgrind-mysqld Run the "mysqld" executable with valgrind.
valgrind-mysqltest Run the "mysqltest" and "mysql_client_test" executable
with valgrind.
valgrind-option=ARGS Option to give valgrind, replaces default option(s), can
be specified more then once.
valgrind-options=ARGS Deprecated, use --valgrind-option.
valgrind-path= Path to the valgrind executable.
从代码看:
- 支持的工具不仅限于 callgrind、helgrind,还支持 memcheck、massif 。
- 只有启用
--valgrind
或--valgrind-mysqltest
选项,才会用到mysql_client_test
。
使用方法
编译选项: -DWITH_DEBUG=1 -DWITH_VALGRIND=1
使用建议:
1、推荐指令可参考 mysql-test/collections/
目录下的文件 default.daily-valgrind
、default.push-valgrind
、default.weekly-valgrind
。
2、据我实测,如需测试 valgrind 所有功能,需在原有指令基础上添加--valgrind
选项。比如:
# 官方 collections 中的示例指令:
perl mysql-test-run.pl --timer --force --skip-rpl --comment=all_default_valgrind --vardir=var-all_default_valgrind --skip-ndb
# 添加 --valgrind
perl mysql-test-run.pl --timer --force --skip-rpl --comment=all_default_valgrind --vardir=var-all_default_valgrind --skip-ndb --valgrind
3、在同时启用 ASAN 和 valgrind 的情况下,并在运行 mtr 时添加--valgrind
选项,mtr 会因 valgrind memcheck 与 asan 冲突而 crash,因此,valgrind 与 asan 不建议同时启用。
Sanitizier
Sanitizers 是谷歌发起的开源工具集,已经成为静态和动态代码分析的利器,可以检查内存错误、未初始化的读取、线程安全和未定义的行为等相关的问题。
优点:与同类型分析工具相比,Sanitizers 带来的性能损失通常要小得多,而且往往提供的信息更详细。
缺点:代码(可能还有工具链的一部分)需要使用附加的标志重新编译。
Sanitizers 包括如下组件:
-
AddressSanitizer/ASAN
检查内存地址相关问题,包括内存泄漏、释放后使用、重复释放、堆溢出、栈溢出等问题。
通过编译插桩(CTI) ,能够发现此堆/栈/全局变量读写溢出,内存泄露等问题,并将信息直接打印到日志中。
ASAN 是一个快速的内存错误检测工具。它非常快,只拖慢程序两倍左右(比起 Valgrind 快多了)。
它包括一个编译器 instrumentation 模块和一个提供
malloc()/free()
替代项的运行时库。 -
LeakSanitizer/LSAN
检查内存泄漏问题。它是集成在 Address Sanitizer 中的一个相对独立的工具,它工作在检查过程的最后阶段。
-
UndefinedBehaviorSanitizer/UBSAN
检测未定义行为(使用空指针、有符号整数溢出等)。
-
ThreadSanitizer/TSAN
检查线程数据竞争和死锁问题。
-
MemorySanitizer/MSAN
检查使用未初始化内存问题。
-
内核 Sanitizer包括KASAN和KMSAN
Sanitizers 项目本是 LLVM 项目的一部分,但 GNU 也将该系列工具加入到了自家的 GCC 编译器中(clang 当然也支持)。
- GCC 4.8 版本开始支持 Address Sanitizer和 Thread Sanitizer。
- GCC 4.9 版本开始支持 Leak Sanitizer 和 UndefinedBehaviorSanitizer。
ASAN
简介
ASAN/AddressSanitizer 能检测很多种内存错误,主要包含如下类别:
- Out-of-bounds accesses to heap, stack and globals
- Use-after-free
-
Use-after-return (clang flag
-fsanitize-address-use-after-return=(never|runtime|always)
default:runtime
)- Enable with:
ASAN_OPTIONS=detect_stack_use_after_return=1
(already enabled on Linux). - Disable with:
ASAN_OPTIONS=detect_stack_use_after_return=0
.
- Enable with:
-
Use-after-scope (clang flag
-fsanitize-address-use-after-scope
) - Double-free, invalid free
- Memory leaks (experimental)
更详细的示例 case:参考 https://learn.microsoft.com/zh-cn/cpp/sanitizers/asan-error-examples?view=msvc-170
- alloc-dealloc-mismatch
- allocation-size-too-big
- calloc-overflow
- container-overflow
- double-free
- dynamic-stack-buffer-overflow
- global-buffer-overflow
- heap-buffer-overflow
- heap-use-after-free
- invalid-allocation-alignment
- memcpy-param-overlap
- new-delete-type-mismatch
- stack-buffer-overflow
- stack-buffer-underflow
- stack-use-after-return
- stack-use-after-scope
- strncat-param-overlap
- use-after-poison
性能影响:使用 ASAN 后,性能会降低 2 倍。
使用方法
安装:有一个单独的动态库libasan6.so
,会随 gcc 安装。
编译选项:-DWITH_DEBUG=1 -DWITH_ASAN=1
,可选择启用-DWITH_ASAN_SCOPE=1
验证版本:8.0.29
MTR 选项:--sanitize
使用建议:
1、ASAN 功能强大,相较于 valgrind,对性能影响小很多,建议作为主要的内存检测工具。
2、由于 mtr 需要用到/usr/bin/perl
,因此,有可能出现 perl 自身某些函数的内存泄漏问题被 Leak Sanitizer 检测到,导致 mtr 测试失败,此时,将问题函数添加到lsan.supp
文件即可解决。比如 Ubuntu 22.04 perl v5.34.0 会遇到内存泄漏,同样的,Ubuntu 20.04 perl v5.30.0 就无该问题。
mysql-test/asan.supp 示例
# 语法
interceptor_via_fun:NameOfCFunctionToSuppress
interceptor_via_fun:-[ClassName objCMethodToSuppress:]
interceptor_via_lib:NameOfTheLibraryToSuppress
# 示例
interceptor_via_fun:Perl_safesyscalloc
interceptor_via_fun:Perl_safesysmalloc
参考:
- asan 文档
- gcc/asan_suppressions.cpp at master · gcc-mirror/gcc · GitHub
mysql-test/lsan.supp 示例
# LSAN suppressions for gcc/clang
leak:Perl_safesyscalloc
leak:Perl_safesysmalloc
leak:Perl_safesysrealloc
leak:Perl_savesharedpv
leak:Perl_Slab_Alloc
leak:Perl_newUNOP_AUX
leak:Perl_newSTATEOP
leak:Perl_pmruntime
leak:/usr/bin/perl
leak:/lib64/libperl.so.*
leak:/bin/bash
leak:/usr/bin/zip
# OpenLDAP bug 9081
# Fixed in 2.4.49, we build with 2.4.48
leak:ldap_initialize
# sasl_client_init will load all available plugins with _sasl_load_plugins().
# It seems some of the SASL plugin have leaks.
# Both LSAN and Valgrind report leaks.
leak:sasl_client_add_plugin
该内容来源于源码文件,可见官方知晓 Perl 高版本的内存泄漏问题,以此方式来忽略。
指令示例
在Ubuntu 22.04 X86_64
运行:
perl mysql-test-run.pl --timer --max-test-fail=0 --force --parallel=1 --vardir=var-rpl --suite=rpl --sanitize
perl mysql-test-run.pl --timer --max-test-fail=0 --force --parallel=1 --max-test-fail=0 --vardir=var-binlog --suite=binlog --sanitize
LSAN
简介
LSAN/LeakSanitizer 用于内存泄漏检测。
性能影响:使用 LSAN 后,除了执行的最后阶段会有一个内存泄漏检测之外,几乎没有性能开销。
使用方法
安装:有一个单独的动态库liblsan0.so
,会随 gcc 安装。
编译选项:-DWITH_DEBUG=1 -DWITH_LSAN=1
验证版本:8.0.29
MTR 选项:--sanitize
使用建议:
- 由于 ASAN 集成了 LSAN,因此,只有不使用 ASAN、仅使用 LSAN 的情况下才需要设置该选项。
-
lsan.supp
格式见 「ASAN」小节。
指令示例
只要编译时启用 ASAN 或 LSAN,在运行时添加--sanitize
选项即可。
perl mysql-test-run.pl --timer --max-test-fail=0 --force --parallel=1 --max-test-fail=0 --vardir=var-binlog --suite=binlog --sanitize
UBSAN
简介
UBSAN/UndefinedBehaviorSanitizer 是针对未定义行为的检测器,速度很快。
UBSAN 需要在编译时修改程序,以捕获程序执行期间的各种未定义行为。比如:
- 数组下标越界:Array subscript out of bounds, where the bounds can be statically determined
- 位移位超过数据类型边界:Bitwise shifts that are out of bounds for their data type
- 解除对未对齐指针或空指针的关联:Dereferencing misaligned or null pointers
- 有符号整数溢出:Signed integer overflow
- 浮点数类型转换导致的溢出:Conversion to, from, or between floating-point types which would overflow the destination
更多行为详见 :
UndefinedBehaviorSanitizer — Clang 17.0.0git documentation (llvm.org)
性能影响:UBSAN 的运行时成本很小,对地址空间布局或 ABI 没有影响。
使用方法
安装:有一个单独的动态库libubsan1.so
,会随 gcc 安装。
编译选项:-DWITH_DEBUG=1 -DWITH_UBSAN=1
验证版本:8.0.29
MTR 选项:--sanitize
使用建议:
- 与 ASAN、TSAN、gcov、gprof 都兼容,可一起启用。
- 若想要某些 case 跳过 UBSAN 的检查,可引用
include/not_ubsan.inc
。目前只有如下 case 会跳过 UBSAN:
./t/innodb_tmp_table_heap_to_disk.test
./t/ssl-big.test
./t/count_distinct3.test
./t/multi_update2.test
./t/ds_mrr-big.test
./suite/gis/t/gis_not_ubsan.test
./suite/binlog_gtid/t/binlog_warning_same_server_id.test
指令示例
只要编译时启用 UBSAN,在运行时添加--sanitize
选项即可。
perl mysql-test-run.pl --timer --max-test-fail=0 --force --parallel=1 --max-test-fail=0 --vardir=var-binlog --suite=binlog --sanitize
TSAN
简介
TSAN/ThreadSanitizer 是用于检测数据竞争和线程死锁的工具。
性能影响:引入 TSAN 后,会降低 5-15 倍性能,同时,内存占用率会提升 5-10 倍。
使用方法
安装:有一个单独的动态库libtsan0.so
,会随 gcc 安装。
编译选项:-DWITH_DEBUG=1 -DWITH_TSAN=1
验证版本:8.0.29、8.0.32
MTR 选项:--sanitize
使用建议:
1、TSAN 与 ASAN 不兼容(一起使用 cmake 会报错"No mysys timer support detected"
),但TSAN 与 UBSAN、VALGRIND 兼容。
2、对 TSAN 的支持是实验性的,尚不成熟,不建议使用。
-- Performing Test HAVE_SANITIZE_SCOPE
-- Performing Test HAVE_SANITIZE_SCOPE - Success
CMake Warning at CMakeLists.txt:1101 (MESSAGE):
Thread sanitizer support is currently experimental.
-- Performing Test C_LD_LLD_RESULT
-- Performing Test C_LD_LLD_RESULT - Failed
-- Performing Test CXX_LD_LLD_RESULT
-- Performing Test CXX_LD_LLD_RESULT - Failed
-- Performing Test C_LD_GOLD_RESULT
-- Performing Test C_LD_GOLD_RESULT - Failed
-- Performing Test CXX_LD_GOLD_RESULT
-- Performing Test CXX_LD_GOLD_RESULT - Failed
-- Local boost dir /data/work/mysql/boost_1_77_0
-- Found /data/work/mysql/boost_1_77_0/boost/version.hpp
-- BOOST_VERSION_NUMBER is #define BOOST_VERSION 107700
-- BOOST_INCLUDE_DIR /data/work/mysql/boost_1_77_0
-- Looking for pthread.h
-- Looking for pthread.h - not found
-- Could NOT find Threads (missing: Threads_FOUND)
......
-- Looking for timer_create # 由于 timer_create/timer_settime 函数确实存在,尝试调整过 cmake,后续会报一系列错误,该问题不太好调。
-- Looking for timer_create - not found
-- Looking for timer_settime
-- Looking for timer_settime - not found
-- Looking for kqueue
-- Looking for kqueue - not found
-- Performing Test HAVE_SETNS
-- Performing Test HAVE_SETNS - Failed
-- Looking for EVFILT_TIMER
-- Looking for EVFILT_TIMER - not found
CMake Error at configure.cmake:334 (MESSAGE):
No mysys timer support detected!
Call Stack (most recent call first):
CMakeLists.txt:1487 (INCLUDE)
3、如果某些数据竞争或死锁情况是符合预期的,可以通过 mysql-test/tsan.supp
跳过。
mysql-test/tsan.supp 示例
#
# Blacklist for Thread Sanitizer.
# Thread Sanitizer can be enabled with -DWITH_TSAN=1
#
# Suppression syntax is documented here:
# https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions
#
race:innobase
race:client/dump/
deadlock:client/dump/
race:perfschema
race:plugin_vars_free_values
race:log_builtins_filter_run
race:MY_LOCALE_ERRMSGS::destroy
race:get_one_variable_ext
race:mysql_set_character_set_with_default_collation
race:ngs::Scheduler_dynamic::wait_if_idle_then_delete_worker
race:ngs::Socket_events::break_loop
deadlock:find_sys_var_ex
deadlock:Persisted_variables_cache::lock
signal:my_print_stacktrace
指令示例
只要编译时启用 TSAN,在运行时添加--sanitize
选项即可。
perl mysql-test-run.pl --timer --max-test-fail=0 --force --parallel=1 --max-test-fail=0 --vardir=var-binlog --suite=binlog --sanitize
存在问题
测试时,在 install database 阶段,线程之间就会有大量 data race,报错示例如下:
// 报错信息位于 mysql-test/var-main-tsan/log/bootstrap.log
==================
WARNING: ThreadSanitizer: data race (pid=65314)
Read of size 4 at 0x555ae20c13b0 by thread T4:
#0 fil_validate_skip /data/work/mysql/mysql-server/storage/innobase/fil/fil0fil.cc:1953 (mysqld+0x541018e)
#1 fil_aio_wait(unsigned long) /data/work/mysql/mysql-server/storage/innobase/fil/fil0fil.cc:8234 (mysqld+0x54109ca)
#2 io_handler_thread /data/work/mysql/mysql-server/storage/innobase/srv/srv0start.cc:279 (mysqld+0x5143b04)
......
#12 std::thread::_State_impl > >::_M_run() /usr/include/c++/11/bits/std_thread.h:211 (mysqld+0x5159b59)
#13 (libstdc++.so.6+0xdc2b2)
Previous write of size 4 at 0x555ae20c13b0 by thread T3:
#0 fil_validate_skip /data/work/mysql/mysql-server/storage/innobase/fil/fil0fil.cc:1953 (mysqld+0x54101a7)
#1 fil_aio_wait(unsigned long) /data/work/mysql/mysql-server/storage/innobase/fil/fil0fil.cc:8234 (mysqld+0x54109ca)
#2 io_handler_thread /data/work/mysql/mysql-server/storage/innobase/srv/srv0start.cc:279 (mysqld+0x5143b04)
......
#12 std::thread::_State_impl > >::_M_run() /usr/include/c++/11/bits/std_thread.h:211 (mysqld+0x5159b59)
#13 (libstdc++.so.6+0xdc2b2)
Location is global 'fil_validate_skip()::fil_validate_count' of size 4 at 0x555ae20c13b0 (mysqld+0x000007a5c3b0)
Thread T4 (tid=65320, running) created by thread T1 at:
#0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
#1 std::thread::_M_start_thread(std::unique_ptr >, void (*)()) (libstdc++.so.6+0xdc388)
......
#8 handle_bootstrap /data/work/mysql/mysql-server/sql/bootstrap.cc:327 (mysqld+0x387778f)
#9 pfs_spawn_thread /data/work/mysql/mysql-server/storage/perfschema/pfs.cc:2942 (mysqld+0x56751fb)
Thread T3 (tid=65319, running) created by thread T1 at:
#0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
#1 std::thread::_M_start_thread(std::unique_ptr >, void (*)()) (libstdc++.so.6+0xdc388)
......
#8 handle_bootstrap /data/work/mysql/mysql-server/sql/bootstrap.cc:327 (mysqld+0x387778f)
#9 pfs_spawn_thread /data/work/mysql/mysql-server/storage/perfschema/pfs.cc:2942 (mysqld+0x56751fb)
SUMMARY: ThreadSanitizer: data race /data/work/mysql/mysql-server/storage/innobase/fil/fil0fil.cc:1953 in fil_validate_skip
==================
......
install database 阶段,类似的报错有 200 多个。虽然可以通过tsan.supp
文件跳过,但毕竟报错涉及较多函数,若全部跳过,可能会影响对正常情况下数据竞争的判断。因此,个人暂不建议使用。
MSAN
简介
MSAN/MemorySanitizer 用于检测对未初始化内存的读取(uninitialized reads)问题。
性能影响:引入 MSAN 后,性能会降低 3 倍。
使用方法
编译选项:-DWITH_DEBUG=1 -DWITH_MSAN=1
验证版本:8.0.29
MTR 选项:--sanitize
使用建议:
- 对 MSAN 的支持是实验性的,尚不成熟,且与 ASAN 不兼容,考虑到 ASAN 的强大,因此,建议使用 ASAN,不建议使用 MSAN。
CMake Warning at CMakeLists.txt:1080 (MESSAGE):
Memory sanitizer support is currently experimental.
CMake Error at CMakeLists.txt:1107 (MESSAGE):
Cannot use AddressSanitizer and MemorySanitizer together
指令示例
只要编译时启用 MSAN,在运行时添加--sanitize
选项即可。
perl mysql-test-run.pl --timer --max-test-fail=0 --force --parallel=1 --max-test-fail=0 --vardir=var-binlog --suite=binlog --sanitize
代码覆盖率测试
简介
gcov 用于分析代码覆盖率,gprof 用于分析 gcov 生成的统计数据,二者一般一起使用。
gprof 只支持 linux 操作系统,不支持 MacOS。
官方手册:
Gcov (Using the GNU Compiler Collection (GCC))
gprof(1) – Linux manual page (man7.org)
超级方便的 Linux 自带性能分析工具!gprof 介绍、安装、使用及实践 – 知乎 (zhihu.com)
使用方法
编译选项:-DWITH_DEBUG=1 -DENABLE_GCOV=1 -DENABLE_GPROF=1
使用建议:
- 与 ASAN、UBSAN 兼容,建议与 ASAN、UBSAN 同时启用(未验证与 valgrind、MSAN、TSAN 的兼容性)。
- 不能在
make install
的安装目录测试,必须在 执行编译的源码目录测试。-
源码根目录/build-debug/mysql-test/mysql-test-run.pl
(本人的编译目录是 build-debug)只是封装了一层对源码根目录/mysql-test/mysql-test-run.pl
的调用:
-
[apps@node6 mysql-test]$ pwd
/home/apps/mtr/mysql-oracle/mysql-8.0.26/build-debug/mysql-test
[apps@node6 mysql-test]$ cat mysql-test-run.pl
#!/usr/bin/perl
# Call mtr in out-of-source build
$ENV{MTR_BINDIR} = '/home/apps/mtr/mysql-oracle/mysql-8.0.26/build-debug';
chdir('/home/apps/mtr/mysql-oracle/mysql-8.0.26/mysql-test');
exit(system($^X, '/home/apps/mtr/mysql-oracle/mysql-8.0.26/mysql-test/mysql-test-run.pl', @ARGV) >> 8);
注意:
- gcov、gprof 运行需要较大内存,尤其是开启
-big-test
的情况下。 - 官方
collections/
中没有 gcov 的推荐用法。 -
mysql-test/README.gcov
文件的最后修改日期是 2006 年,已过时,没有参考价值。
示例
直接在安装目录(make install
)执行测试,报错:
wslu@ubuntu:/data/work/mysql/mysql80-install.bak_asan_ubsan_gcov_gprof/mysql-test$ ./mtr --gcov
Logging: ./mtr --gcov
MySQL Version 8.0.29
mysql-test-run: *** ERROR: Coverage test needs the source - please use source dist
在执行编译的目录(比如 console-build-debug/mysql-test
) 执行:
wslu@ubuntu:/data/work/mysql/mysql-server/console-build-debug/mysql-test$ ./mtr --gcov -big-test
Logging: /data/work/mysql/mysql-server/mysql-test/mysql-test-run.pl --gcov -big-test
MySQL Version 8.0.29
Checking supported features
- Binaries are debug compiled
Purging gcov information from '/data/work/mysql/mysql-server'...
Using suite(s): auth_sec,binlog,binlog_gtid,binlog_nogtid,clone,collations,component_keyring_file,connection_control,encryption,federated,funcs_2,gcol,gis,information_schema,innodb,innodb_fts,innodb_gis,innodb_undo,innodb_zip,interactive_utilities,json,main,opt_trace,parts,perfschema,query_rewrite_plugins,rpl,rpl_gtid,rpl_nogtid,secondary_engine,service_status_var_registration,service_sys_var_registration,service_udf_registration,sys_vars,sysschema,test_service_sql_api,test_services,x
Collecting tests
- Adding combinations for binlog
- Adding combinations for binlog_gtid
- Adding combinations for binlog_nogtid
- Adding combinations for rpl
- Adding combinations for rpl_gtid
- Adding combinations for rpl_nogtid
Checking leftover processes
Removing old var directory
Creating var directory '/data/work/mysql/mysql-server/console-build-debug/mysql-test/var'
Installing system database
Using parallel: 1
==============================================================================
TEST NAME RESULT TIME (ms) COMMENT
------------------------------------------------------------------------------
[ 0%] binlog_gtid.binlog_xa_select_gtid_executed_explicitly_crash [ disabled ] Bug#28588717 Fails both on FreeBSD and other platforms
[ 0%] binlog_nogtid.binlog_gtid_next_xa [ disabled ] BUG#33650776 Failure of XA COMMIT of prepared txn, can result in txn rollback
[ 0%] sys_vars.innodb_log_writer_threads_basic [ disabled ] Bug#32129814 SYS_VARS.INNODB_LOG_WRITER_THREADS_BASIC TIMES OUT SPORADICALLY ON PB2
[ 0%] sysschema.v_wait_classes_global_by_avg_latency [ disabled ] BUG#21550054 Test fails too often.
[ 0%] binlog_gtid.binlog_gtid_mix_ok_packet_all_gtids 'mix' [ pass ] 770
[ 0%] binlog_gtid.binlog_gtid_mix_response_packet 'mix' [ pass ] 6474
[ 0%] binlog_gtid.binlog_xa_trx_gtid_response_packet 'mix' [ pass ] 683
......
[ 0%] binlog_gtid.binlog_gtid_errors 'mix' [ pass ] 1583
......
如果想执行测试后分析 gmon.out
,则可添加 -gprof
参数(仅支持 linux):
wslu@ubuntu:/data/work/mysql/mysql-server/console-build-debug/mysql-test$ ./mtr --gcov -gprof -big-test
那么,在 gcov 执行完成后,mtr 就会自动调用 gprof 解析gmon.out
文件。
存在问题
但在 CentOS 7.6(云服务器 4C8G SSD)实测时遇到问题——gprof 解析 gmon.out 时特别耗时,虽然该进程 CPU 占用率 100%,看起来还在运行,但并无任何输出。
比如,在编译的源码目录中执行:
➜ mysql-test git:(heads/mysql-8.0.26) ✗ ps -axf | grep mysql
30604 ? SN 0:00 _ perl mysql-test-run.pl --parallel=4 --timer --debug-server --force --testcase-timeout=180 --suite-timeout=1800 --comment=all-default-debug --vardir=var-all-default --skip-combinations --unit-tests-report --no-skip --exclude-platform=windows --skip-ndb --max-test-fail=0 --suite=rpl -gcov -gprof
30611 ? SN 0:30 _ /usr/bin/perl /home/wslu/work/mysql/mysql-server/mysql-test/mysql-test-run.pl --parallel=4 --timer --debug-server --force --testcase-timeout=180 --suite-timeout=1800 --comment=all-default-debug --vardir=var-all-default --skip-combinations --unit-tests-report --no-skip --exclude-platform=windows --skip-ndb --max-test-fail=0 --suite=rpl -gcov -gprof
32759 ? SN 0:44 _ /usr/bin/perl /home/wslu/work/mysql/mysql-server/mysql-test/mysql-test-run.pl --parallel=4 --timer --debug-server --force --testcase-timeout=180 --suite-timeout=1800 --comment=all-default-debug --vardir=var-all-default --skip-combinations --unit-tests-report --no-skip --exclude-platform=windows --skip-ndb --max-test-fail=0 --suite=rpl -gcov -gprof
2829 ? SN 0:00 | _ sh -c gprof /home/wslu/work/mysql/mysql-server/build-debug/runtime_output_directory/mysqld /home/wslu/work/mysql/mysql-server/mysql-test/var-all-default/3/mysqld.6/data/gmon.out 2 > /home/wslu/work/mysql/mysql-server/mysql-test/var-all-default/3/mysqld.6/data/gprof.err > /home/wslu/work/mysql/mysql-server/mysql-test/var-all-default/3/mysqld.6/data/gprof.msg
2830 ? RN 7:07 | _ gprof /home/wslu/work/mysql/mysql-server/build-debug/runtime_output_directory/mysqld /home/wslu/work/mysql/mysql-server/mysql-test/var-all-default/3/mysqld.6/data/gmon.out 2
gmon.out 文件只有 61MB,但 gprof 在解析 gmon.out
时,长达 23 小时无任何输出。
➜ mysql-test git:(heads/mysql-8.0.26) ✗ ls /home/wslu/work/mysql/mysql-server/mysql-test/var-all-default/3/mysqld.6/data/gmon.out -lh
-rw-r--r-- 1 wslu wslu 61M Mar 27 20:21 /home/wslu/work/mysql/mysql-server/mysql-test/var-all-default/3/mysqld.6/data/gmon.out
➜ mysql-test git:(heads/mysql-8.0.26) ✗ ll /home/wslu/work/mysql/mysql-server/mysql-test/var-all-default/3/mysqld.6/data/gprof.err
-rw-r--r-- 1 wslu wslu 0 Mar 28 09:23 /home/wslu/work/mysql/mysql-server/mysql-test/var-all-default/3/mysqld.6/data/gprof.err
➜ mysql-test git:(heads/mysql-8.0.26) ✗ ll /home/wslu/work/mysql/mysql-server/mysql-test/var-all-default/3/mysqld.6/data/gprof.msg
-rw-r--r-- 1 wslu wslu 0 Mar 28 09:23 /home/wslu/work/mysql/mysql-server/mysql-test/var-all-default/3/mysqld.6/data/gprof.msg
单元测试
简介
MySQL 使用 TAP(Test Anything Protocol) 和 Google Test Framework 来实现单元测试。
MyTAP
TAP 是 Perl 与测试模块之间所使用的简单的基于文本的接口,主要用于开发 Perl 和 PHP 模块。示例如下:
TAP version 13
ok 1 - testNewArrayIsEmpty(ArrayTest)
ok 2 - testArrayContainsAnElement(ArrayTest)
not ok 3 - Failure: testFailure(FailureErrorTest)
---
message: 'Failed asserting that
|
||||
|
||||
|
||||
|
|
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.e1idc.net