ThreadSanitizer
-
-
- 1. 介绍
- 2. 如何构建
- 3. 支持的平台
- 4. 使用(Usage)
-
-
- 4.1 __has_feature(thread_sanitizer)
- 4.2 __attribute__((no_sanitize("thread")))
-
- 5. 黑名单(Blacklist)
- 6. 限制
- 7. 当前的状态
- 8. 更多的信息
-
本文为译文,点击 此处查看原文。
1. 介绍
ThreadSanitizer
是一个检测数据竞争的工具。它由编译器检测模块和运行时库组成。
ThreadSanitizer
引入的典型减速是 5x-15x 左右。
ThreadSanitizer
引入的典型内存开销约为5x-10x。
2. 如何构建
使用 CMake 构建 LLVM/Clang。
3. 支持的平台
ThreadSanitizer
支持以下操作系统:
- Android aarch64 x86_64
- Darwin arm64 x86_64
- FreeBSD
- Linux aarch64, x86_64, powerpc64, powerpc64le
- NetBSD
支持其他64位体系结构是可能的,欢迎贡献。对32位平台的支持存在问题,而且没有计划。
4. 使用(Usage)
只需用
-fsanitize=thread
编译并链接程序。要获得合理的性能,请添加
-O1
或更高。使用
-g
获取警告消息中的文件名和行号。
例子:
% cat projects/compiler-rt/lib/tsan/lit_tests/tiny_race.c
#include <pthread.h>
int Global;
void *Thread1(void *x) {
Global = 42;
return x;
}
int main() {
pthread_t t;
pthread_create(&t, NULL, Thread1, NULL);
Global = 43;
pthread_join(t, NULL);
return Global;
}
$ clang -fsanitize=thread -g -O1 tiny_race.c
如果检测到一个 bug,程序将向 stderr 打印一条错误消息。目前,
ThreadSanitizer
使用外部
addr2line
进程来表示它的输出(这将在将来得到修复)。
% ./a.out
WARNING: ThreadSanitizer: data race (pid=19219)
Write of size 4 at 0x7fcf47b21bc0 by thread T1:
#0 Thread1 tiny_race.c:4 (exe+0x00000000a360)
Previous write of size 4 at 0x7fcf47b21bc0 by main thread:
#0 main tiny_race.c:10 (exe+0x00000000a3b4)
Thread T1 (running) created at:
#0 pthread_create tsan_interceptors.cc:705 (exe+0x00000000c790)
#1 main tiny_race.c:9 (exe+0x00000000a3a4)
4.1 __has_feature(thread_sanitizer)
在某些情况下,可能需要执行不同的代码,这取决于是否启用了
ThreadSanitizer
。可以为此目的使用_has_feature。
#if defined(__has_feature)
# if __has_feature(thread_sanitizer)
// code that builds only under ThreadSanitizer
# endif
#endif
4.2 attribute((no_sanitize(“thread”)))
有些代码不应该用
ThreadSanitizer
检测。可以使用函数属性
no_sanitize(“thread”)
禁用特定函数中普通(非原子)加载/存储的检测。
ThreadSanitizer
仍然使用这些函数来避免误报,并提供有意义的堆栈跟踪。其他编译器可能不支持此属性,因此我们建议将其与
__has_feature(thread_sanitizer)
一起使用。
5. 黑名单(Blacklist)
ThreadSanitizer
支持 Sanitizer special case list 中的
src
和
fun
实体类型,可以用于在指定的源文件或函数中禁止数据竞争报告。与标记为
no_sanitize(“thread”)
属性的函数不同,黑名单函数根本不插桩。这可能导致误报,原因是通过原子操作错过了同步和报告中错过了堆栈帧。
6. 限制
-
比本机运行使用更多的实际内存。在默认设置下,每个线程的内存开销是5x + 1Mb。使用3x(不太精确的分析)和9x(更精确的分析)开销的设置也是可用的。ThreadSanitizer
-
映射(但不保留)大量的虚拟地址空间。这意味着像ThreadSanitizer
这样的工具可能不会像通常预期的那样工作。ulimit
- 不支持
静态链接。Libc/libstdc++
- 不支持非位置独立的可执行程序。因此,如果编译时没有
,-fPIC
标志将导致 Clang 的行为,就好像已经提供了fsanitize=thread
标志一样,如果链接一个可执行文件,就好像已经提供了-fPIE
标志一样。-pie
7. 当前的状态
ThreadSanitizer
还在测试阶段。众所周知,它可以在使用 pthread 的大型 C++ 程序上工作,但是我们(目前)还没有做出任何承诺。C++ 11 线程由 llvm libc++ 支持。测试套件集成到 CMake build 中,可以使用
make check-tsan
命令运行。
我们正在积极地改进这个工具 —— 请继续关注。任何帮助,特别是以最小化的独立测试的形式,都是非常受欢迎的。
8. 更多的信息
https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual