Skip to content

Commit 73c2977

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm] More workarounds for false-positives in the profiler due to TSAN not understanding thread_suspend.
TEST=tsan Bug: #61509 Change-Id: I4e8e2d949f4df88bb401dbe5997b59491988c05a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/450102 Reviewed-by: Alexander Aprelev <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent b8cf6ba commit 73c2977

File tree

6 files changed

+59
-17
lines changed

6 files changed

+59
-17
lines changed

runtime/vm/os_thread.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "platform/globals.h"
1010
#include "platform/safe_stack.h"
1111
#include "platform/synchronization.h"
12+
#include "platform/thread_sanitizer.h"
1213
#include "platform/threads.h"
1314
#include "platform/utils.h"
1415
#include "vm/allocation.h"
@@ -247,6 +248,8 @@ class OSThread : public BaseThread {
247248
// We could eliminate this requirement if the windows thread interrupter
248249
// is implemented differently.
249250
ThreadState* thread() const { return thread_; }
251+
NO_SANITIZE_THREAD
252+
ThreadState* thread_ignore_race() const { return thread_; }
250253
void set_thread(ThreadState* value) { thread_ = value; }
251254

252255
static void Cleanup();

runtime/vm/profiler.cc

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,16 @@ static uword* LoadStackSlot(uword* ptr) {
209209
return reinterpret_cast<uword*>(*ptr);
210210
}
211211

212+
#if defined(DART_HOST_OS_MACOS)
213+
// Mac profiling is cross-thread and TSAN doesn't know that thread_suspend
214+
// establishes synchronization.
215+
#define IGNORE_RACE(x) x##_ignore_race
216+
#define IGNORE_RACE2(x) x##IgnoreRace
217+
#else
218+
#define IGNORE_RACE(x) x
219+
#define IGNORE_RACE2(x) x
220+
#endif
221+
212222
// The layout of C stack frames.
213223
#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64) || \
214224
defined(HOST_ARCH_ARM) || defined(HOST_ARCH_ARM64)
@@ -379,7 +389,8 @@ static bool GetAndValidateThreadStackBounds(OSThread* os_thread,
379389

380390
#if defined(DART_INCLUDE_SIMULATOR)
381391
const bool use_simulator_stack_bounds =
382-
FLAG_use_simulator && thread != nullptr && thread->IsExecutingDartCode();
392+
FLAG_use_simulator && thread != nullptr &&
393+
thread->IGNORE_RACE2(IsExecutingDartCode)();
383394
if (use_simulator_stack_bounds) {
384395
Isolate* isolate = thread->isolate();
385396
ASSERT(isolate != nullptr);
@@ -1047,8 +1058,8 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
10471058
uword lr,
10481059
bool allocation_sample,
10491060
intptr_t skip_count = 0)
1050-
: ProfilerStackWalker((thread->isolate() != nullptr)
1051-
? thread->isolate()->main_port()
1061+
: ProfilerStackWalker((thread->IGNORE_RACE(isolate)() != nullptr)
1062+
? thread->IGNORE_RACE(isolate)()->main_port()
10521063
: ILLEGAL_PORT,
10531064
sample,
10541065
sample_buffer,
@@ -1061,12 +1072,13 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
10611072

10621073
void walk() {
10631074
RELEASE_ASSERT(StubCode::HasBeenInitialized());
1064-
if (thread_->IsDeoptimizing()) {
1075+
if (thread_->IGNORE_RACE2(IsDeoptimizing)()) {
10651076
sample_->set_ignore_sample(true);
10661077
return;
10671078
}
10681079

1069-
uword* exit_fp = reinterpret_cast<uword*>(thread_->top_exit_frame_info());
1080+
uword* exit_fp =
1081+
reinterpret_cast<uword*>(thread_->IGNORE_RACE(top_exit_frame_info)());
10701082
bool has_exit_frame = exit_fp != nullptr;
10711083
if (has_exit_frame) {
10721084
// Exited from compiled code or interpreter.
@@ -1077,13 +1089,14 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
10771089
pc_ = CallerPC();
10781090
fp_ = CallerFP();
10791091
} else {
1080-
if (thread_->vm_tag() == VMTag::kDartTagId) {
1092+
if (thread_->IGNORE_RACE(vm_tag)() == VMTag::kDartTagId) {
10811093
// Running compiled code.
10821094
// Use the FP and PC from the thread interrupt or simulator; already set
10831095
// in the constructor.
10841096

10851097
#if defined(DART_DYNAMIC_MODULES)
1086-
} else if (thread_->vm_tag() == VMTag::kDartInterpretedTagId) {
1098+
} else if (thread_->IGNORE_RACE(vm_tag)() ==
1099+
VMTag::kDartInterpretedTagId) {
10871100
// Running interpreter.
10881101
pc_ = reinterpret_cast<uword*>(thread_->interpreter()->get_pc());
10891102
fp_ = reinterpret_cast<uword*>(thread_->interpreter()->get_fp());
@@ -1286,15 +1299,15 @@ static Sample* SetupSample(Thread* thread,
12861299
bool allocation_sample,
12871300
ThreadId tid) {
12881301
ASSERT(thread != nullptr);
1289-
Isolate* isolate = thread->isolate();
1302+
Isolate* isolate = thread->IGNORE_RACE(isolate)();
12901303
SampleBlockBuffer* buffer = Profiler::sample_block_buffer();
12911304
Sample* sample = allocation_sample ? buffer->ReserveAllocationSample(isolate)
12921305
: buffer->ReserveCPUSample(isolate);
12931306
if (sample == nullptr) {
12941307
return nullptr;
12951308
}
12961309
sample->Init(isolate->main_port(), OS::GetCurrentMonotonicMicros(), tid);
1297-
uword vm_tag = thread->vm_tag();
1310+
uword vm_tag = thread->IGNORE_RACE(vm_tag)();
12981311
#if defined(DART_INCLUDE_SIMULATOR)
12991312
// When running in the simulator, the runtime entry function address
13001313
// (stored as the vm tag) is the address of a redirect function.
@@ -1307,7 +1320,7 @@ static Sample* SetupSample(Thread* thread,
13071320
}
13081321
#endif
13091322
sample->set_vm_tag(vm_tag);
1310-
sample->set_user_tag(thread->user_tag());
1323+
sample->set_user_tag(thread->IGNORE_RACE(user_tag)());
13111324
sample->set_thread_task(thread->task_kind());
13121325
return sample;
13131326
}
@@ -1388,7 +1401,7 @@ void Profiler::SampleThreadSingleFrame(Thread* thread,
13881401
ASSERT(thread != nullptr);
13891402
OSThread* os_thread = thread->os_thread();
13901403
ASSERT(os_thread != nullptr);
1391-
Isolate* isolate = thread->isolate();
1404+
Isolate* isolate = thread->IGNORE_RACE(isolate)();
13921405

13931406
ASSERT(Profiler::sample_block_buffer() != nullptr);
13941407

@@ -1406,9 +1419,9 @@ void Profiler::SampleThreadSingleFrame(Thread* thread,
14061419
void Profiler::SampleThread(Thread* thread,
14071420
const InterruptedThreadState& state) {
14081421
ASSERT(thread != nullptr);
1409-
OSThread* os_thread = thread->os_thread();
1422+
OSThread* os_thread = thread->IGNORE_RACE(os_thread)();
14101423
ASSERT(os_thread != nullptr);
1411-
Isolate* isolate = thread->isolate();
1424+
Isolate* isolate = thread->IGNORE_RACE(isolate)();
14121425

14131426
// Double check if interrupts are disabled
14141427
// after the thread interrupter decided to send a signal.
@@ -1430,7 +1443,7 @@ void Profiler::SampleThread(Thread* thread,
14301443
return;
14311444
}
14321445

1433-
const bool in_dart_code = thread->IsExecutingDartCode();
1446+
const bool in_dart_code = thread->IGNORE_RACE2(IsExecutingDartCode)();
14341447

14351448
uintptr_t sp = 0;
14361449
uintptr_t fp = state.fp;
@@ -1478,7 +1491,7 @@ void Profiler::SampleThread(Thread* thread,
14781491
}
14791492

14801493
if (thread->IsDartMutatorThread()) {
1481-
if (thread->IsDeoptimizing()) {
1494+
if (thread->IGNORE_RACE2(IsDeoptimizing)()) {
14821495
counters_.single_frame_sample_deoptimizing.fetch_add(1);
14831496
SampleThreadSingleFrame(thread, sample, pc);
14841497
return;
@@ -1509,7 +1522,7 @@ void Profiler::SampleThread(Thread* thread,
15091522
&counters_, (isolate != nullptr) ? isolate->main_port() : ILLEGAL_PORT,
15101523
sample, isolate->current_sample_block(), stack_lower, stack_upper, pc, fp,
15111524
sp);
1512-
const bool exited_dart_code = thread->HasExitedDartCode();
1525+
const bool exited_dart_code = thread->IGNORE_RACE2(HasExitedDartCode)();
15131526
ProfilerDartStackWalker dart_stack_walker(
15141527
thread, sample, isolate->current_sample_block(), pc, fp, sp, lr,
15151528
/* allocation_sample*/ false);

runtime/vm/thread.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,10 +1062,20 @@ bool Thread::IsExecutingDartCode() const {
10621062
return (top_exit_frame_info() == 0) && VMTag::IsDartTag(vm_tag());
10631063
}
10641064

1065+
bool Thread::IsExecutingDartCodeIgnoreRace() const {
1066+
return (top_exit_frame_info_ignore_race() == 0) &&
1067+
VMTag::IsDartTag(vm_tag_ignore_race());
1068+
}
1069+
10651070
bool Thread::HasExitedDartCode() const {
10661071
return (top_exit_frame_info() != 0) && !VMTag::IsDartTag(vm_tag());
10671072
}
10681073

1074+
bool Thread::HasExitedDartCodeIgnoreRace() const {
1075+
return (top_exit_frame_info_ignore_race() != 0) &&
1076+
!VMTag::IsDartTag(vm_tag_ignore_race());
1077+
}
1078+
10691079
template <class C>
10701080
C* Thread::AllocateReusableHandle() {
10711081
C* handle = reinterpret_cast<C*>(reusable_handles_.AllocateScopedHandle());

runtime/vm/thread.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "platform/assert.h"
1717
#include "platform/atomic.h"
1818
#include "platform/safe_stack.h"
19+
#include "platform/thread_sanitizer.h"
1920
#include "vm/bitfield.h"
2021
#include "vm/compiler/runtime_api.h"
2122
#include "vm/constants.h"
@@ -570,6 +571,8 @@ class Thread : public ThreadState, public IntrusiveDListEntry<Thread> {
570571

571572
// The isolate that this thread is operating on, or nullptr if none.
572573
Isolate* isolate() const { return isolate_; }
574+
NO_SANITIZE_THREAD
575+
Isolate* isolate_ignore_race() const { return isolate_; }
573576
static intptr_t isolate_offset() { return OFFSET_OF(Thread, isolate_); }
574577
static intptr_t isolate_group_offset() {
575578
return OFFSET_OF(Thread, isolate_group_);
@@ -625,9 +628,11 @@ class Thread : public ThreadState, public IntrusiveDListEntry<Thread> {
625628

626629
// Is |this| executing Dart code?
627630
bool IsExecutingDartCode() const;
631+
bool IsExecutingDartCodeIgnoreRace() const;
628632

629633
// Has |this| exited Dart code?
630634
bool HasExitedDartCode() const;
635+
bool HasExitedDartCodeIgnoreRace() const;
631636

632637
bool HasCompilerState() const { return compiler_state_ != nullptr; }
633638

@@ -735,6 +740,8 @@ class Thread : public ThreadState, public IntrusiveDListEntry<Thread> {
735740
}
736741

737742
uword top_exit_frame_info() const { return top_exit_frame_info_; }
743+
NO_SANITIZE_THREAD
744+
uword top_exit_frame_info_ignore_race() const { return top_exit_frame_info_; }
738745
void set_top_exit_frame_info(uword top_exit_frame_info) {
739746
top_exit_frame_info_ = top_exit_frame_info;
740747
}
@@ -865,6 +872,8 @@ class Thread : public ThreadState, public IntrusiveDListEntry<Thread> {
865872
#endif
866873

867874
uword vm_tag() const { return vm_tag_; }
875+
NO_SANITIZE_THREAD
876+
uword vm_tag_ignore_race() const { return vm_tag_; }
868877
void set_vm_tag(uword tag) { vm_tag_ = tag; }
869878
static intptr_t vm_tag_offset() { return OFFSET_OF(Thread, vm_tag_); }
870879

@@ -1334,6 +1343,8 @@ class Thread : public ThreadState, public IntrusiveDListEntry<Thread> {
13341343
}
13351344

13361345
bool IsDeoptimizing() const { return deopt_context_ != nullptr; }
1346+
NO_SANITIZE_THREAD
1347+
bool IsDeoptimizingIgnoreRace() const { return deopt_context_ != nullptr; }
13371348
DeoptContext* deopt_context() const { return deopt_context_; }
13381349
void set_deopt_context(DeoptContext* value) {
13391350
ASSERT(value == nullptr || deopt_context_ == nullptr);
@@ -1352,6 +1363,8 @@ class Thread : public ThreadState, public IntrusiveDListEntry<Thread> {
13521363
}
13531364

13541365
uword user_tag() const { return user_tag_; }
1366+
NO_SANITIZE_THREAD
1367+
uword user_tag_ignore_race() const { return user_tag_; }
13551368
static intptr_t user_tag_offset() { return OFFSET_OF(Thread, user_tag_); }
13561369
static intptr_t current_tag_offset() {
13571370
return OFFSET_OF(Thread, current_tag_);

runtime/vm/thread_interrupter_macos.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class ThreadInterrupterMacOS {
7171
kern_return_t res = KERN_FAILURE;
7272
#endif
7373
ASSERT(res == KERN_SUCCESS);
74-
Thread* thread = static_cast<Thread*>(os_thread_->thread());
74+
Thread* thread = static_cast<Thread*>(os_thread_->thread_ignore_race());
7575
if (thread == nullptr) {
7676
return;
7777
}

runtime/vm/thread_state.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define RUNTIME_VM_THREAD_STATE_H_
77

88
#include "include/dart_api.h"
9+
#include "platform/thread_sanitizer.h"
910
#include "vm/os_thread.h"
1011

1112
namespace dart {
@@ -31,6 +32,8 @@ class ThreadState : public BaseThread {
3132

3233
// OSThread corresponding to this thread.
3334
OSThread* os_thread() const { return os_thread_; }
35+
NO_SANITIZE_THREAD
36+
OSThread* os_thread_ignore_race() const { return os_thread_; }
3437
void set_os_thread(OSThread* os_thread) { os_thread_ = os_thread; }
3538

3639
// The topmost zone used for allocation in this thread.

0 commit comments

Comments
 (0)