Skip to content

Commit d190f01

Browse files
authored
[DevTSAN] Support thread sanitizer for device offloading in UR & libdevice (#17345)
This PR is going to support thread sanitizer for device offloading (UR & libdevice part) 1.implemented builtin __tsan_[read|write]N 2.added thread sanitizer layer in UR 3.fallback __TsanLaunchInfo to device global due to GPU driver issue 4.added three e2e tests
1 parent a106550 commit d190f01

File tree

22 files changed

+1883
-115
lines changed

22 files changed

+1883
-115
lines changed

libdevice/atomic.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ extern DEVICE_EXTERNAL void
7979
__spirv_AtomicStore(int *, __spv::Scope::Flag, __spv::MemorySemanticsMask::Flag,
8080
int);
8181

82+
extern DEVICE_EXTERNAL int __spirv_AtomicIAdd(SPIR_GLOBAL int *,
83+
__spv::Scope::Flag,
84+
__spv::MemorySemanticsMask::Flag,
85+
int);
86+
8287
/// Atomically set the value in *Ptr with Desired if and only if it is Expected
8388
/// Return the value which already was in *Ptr
8489
static inline int atomicCompareAndSet(SPIR_GLOBAL int *Ptr, int Desired,
@@ -111,4 +116,10 @@ static inline void atomicStore(int *Ptr, int V) {
111116
__spv::MemorySemanticsMask::SequentiallyConsistent, V);
112117
}
113118

119+
static inline int atomicAdd(SPIR_GLOBAL int *Ptr, int V) {
120+
return __spirv_AtomicIAdd(Ptr, __spv::Scope::Device,
121+
__spv::MemorySemanticsMask::SequentiallyConsistent,
122+
V);
123+
}
124+
114125
#endif // __SPIR__ || __SPIRV__

libdevice/cmake/modules/SYCLLibdevice.cmake

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,14 @@ if (NOT MSVC AND UR_SANITIZER_INCLUDE_DIR)
299299
include/sanitizer_defs.hpp
300300
include/spir_global_var.hpp
301301
sycl-compiler)
302+
303+
set(tsan_obj_deps
304+
device.h atomic.hpp spirv_vars.h
305+
${UR_SANITIZER_INCLUDE_DIR}/tsan/tsan_libdevice.hpp
306+
include/tsan_rtl.hpp
307+
include/sanitizer_defs.hpp
308+
include/spir_global_var.hpp
309+
sycl-compiler)
302310
endif()
303311

304312
if("native_cpu" IN_LIST SYCL_ENABLE_BACKENDS)
@@ -393,6 +401,7 @@ else()
393401
-I${UR_SANITIZER_INCLUDE_DIR}
394402
-I${CMAKE_CURRENT_SOURCE_DIR})
395403

404+
# msan aot
396405
set(msan_devicetypes pvc cpu)
397406

398407
foreach(msan_ft IN LISTS sanitizer_filetypes)
@@ -405,6 +414,13 @@ else()
405414
endforeach()
406415
endforeach()
407416

417+
# tsan jit
418+
add_devicelibs(libsycl-tsan
419+
SRC sanitizer/tsan_rtl.cpp
420+
DEPENDENCIES ${tsan_obj_deps}
421+
EXTRA_OPTS -fno-sycl-instrument-device-code
422+
-I${UR_SANITIZER_INCLUDE_DIR}
423+
-I${CMAKE_CURRENT_SOURCE_DIR})
408424
endif()
409425
endif()
410426

libdevice/include/tsan_rtl.hpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//==-- tsan_rtl.hpp - Declaration for sanitizer global var ---==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
#pragma once
9+
10+
#include "sanitizer_defs.hpp"
11+
#include "spir_global_var.hpp"
12+
#include "tsan/tsan_libdevice.hpp"
13+
14+
// Treat this header as system one to workaround frontend's restriction
15+
#pragma clang system_header
16+
17+
#if defined(__SPIR__) || defined(__SPIRV__)
18+
19+
struct Shadow {
20+
public:
21+
static constexpr RawShadow kEmpty = static_cast<RawShadow>(0);
22+
23+
// A marker to indicate that the current address will not trigger race
24+
// condition.
25+
static constexpr RawShadow kRodata = static_cast<RawShadow>(1 << 30);
26+
27+
Shadow(uint32_t addr, uint32_t size, uint32_t clock, uint32_t sid,
28+
AccessType typ) {
29+
raw_ = 0;
30+
raw_ |= (!!(typ & kAccessAtomic) << 31) | (!!(typ & kAccessRead) << 30) |
31+
(clock << 16) | (sid << 8) |
32+
(((((1u << size) - 1) << (addr & 0x7)) & 0xff));
33+
}
34+
35+
explicit Shadow(RawShadow x = Shadow::kEmpty) {
36+
raw_ = static_cast<uint32_t>(x);
37+
}
38+
39+
RawShadow raw() const { return static_cast<RawShadow>(raw_); }
40+
41+
Sid sid() const { return part_.sid_; }
42+
43+
uint16_t clock() const { return part_.clock_; }
44+
45+
uint8_t access() const { return part_.access_; }
46+
47+
bool IsBothReads(AccessType Type) {
48+
uint32_t is_read = !!(Type & kAccessRead);
49+
bool res = raw_ & (is_read << 30);
50+
return res;
51+
}
52+
53+
private:
54+
struct Parts {
55+
uint8_t access_;
56+
Sid sid_;
57+
uint16_t clock_ : 14;
58+
uint16_t is_read_ : 1;
59+
uint16_t is_atomic_ : 1;
60+
};
61+
union {
62+
Parts part_;
63+
uint32_t raw_;
64+
};
65+
};
66+
67+
#endif // __SPIR__ || __SPIRV__

0 commit comments

Comments
 (0)