Skip to content

Commit 7e28e7d

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[profiler] Don't read from a previous block when a sample overflows to the another block.
TEST=dartfuzz Bug: #61904 Change-Id: I0fd5176502e0d11c5af35f5c27653db8cc294eff Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/459523 Reviewed-by: Alexander Aprelev <aam@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
1 parent 68b5f64 commit 7e28e7d

File tree

3 files changed

+176
-38
lines changed

3 files changed

+176
-38
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// VMOptions=--profiler --profile-vm=true
6+
// VMOptions=--profiler --profile-vm=false
7+
8+
main() {
9+
for (var i = 0; i < 10000; i++) {
10+
foo1();
11+
}
12+
}
13+
14+
@pragma("vm:never-inline")
15+
foo1() => foo2();
16+
@pragma("vm:never-inline")
17+
foo2() => foo3();
18+
@pragma("vm:never-inline")
19+
foo3() => foo4();
20+
@pragma("vm:never-inline")
21+
foo4() => foo5();
22+
@pragma("vm:never-inline")
23+
foo5() => foo6();
24+
@pragma("vm:never-inline")
25+
foo6() => foo7();
26+
@pragma("vm:never-inline")
27+
foo7() => foo8();
28+
@pragma("vm:never-inline")
29+
foo8() => foo9();
30+
@pragma("vm:never-inline")
31+
foo9() => foo10();
32+
@pragma("vm:never-inline")
33+
foo10() => foo11();
34+
@pragma("vm:never-inline")
35+
foo11() => foo12();
36+
@pragma("vm:never-inline")
37+
foo12() => foo13();
38+
@pragma("vm:never-inline")
39+
foo13() => foo14();
40+
@pragma("vm:never-inline")
41+
foo14() => foo15();
42+
@pragma("vm:never-inline")
43+
foo15() => foo16();
44+
@pragma("vm:never-inline")
45+
foo16() => foo17();
46+
@pragma("vm:never-inline")
47+
foo17() => foo18();
48+
@pragma("vm:never-inline")
49+
foo18() => foo19();
50+
@pragma("vm:never-inline")
51+
foo19() => foo20();
52+
@pragma("vm:never-inline")
53+
foo20() => foo21();
54+
@pragma("vm:never-inline")
55+
foo21() => foo22();
56+
@pragma("vm:never-inline")
57+
foo22() => foo23();
58+
@pragma("vm:never-inline")
59+
foo23() => foo24();
60+
@pragma("vm:never-inline")
61+
foo24() => foo25();
62+
@pragma("vm:never-inline")
63+
foo25() => foo26();
64+
@pragma("vm:never-inline")
65+
foo26() => foo27();
66+
@pragma("vm:never-inline")
67+
foo27() => foo28();
68+
@pragma("vm:never-inline")
69+
foo28() => foo29();
70+
@pragma("vm:never-inline")
71+
foo29() => foo30();
72+
@pragma("vm:never-inline")
73+
foo30() => foo31();
74+
@pragma("vm:never-inline")
75+
foo31() => foo32();
76+
@pragma("vm:never-inline")
77+
foo32() => foo33();
78+
@pragma("vm:never-inline")
79+
foo33() => foo34();
80+
@pragma("vm:never-inline")
81+
foo34() => foo35();
82+
@pragma("vm:never-inline")
83+
foo35() => foo36();
84+
@pragma("vm:never-inline")
85+
foo36() => foo37();
86+
@pragma("vm:never-inline")
87+
foo37() => foo38();
88+
@pragma("vm:never-inline")
89+
foo38() => foo39();
90+
@pragma("vm:never-inline")
91+
foo39() => foo40();
92+
@pragma("vm:never-inline")
93+
foo40() => foo41();
94+
@pragma("vm:never-inline")
95+
foo41() => foo42();
96+
@pragma("vm:never-inline")
97+
foo42() => foo43();
98+
@pragma("vm:never-inline")
99+
foo43() => foo44();
100+
@pragma("vm:never-inline")
101+
foo44() => foo45();
102+
@pragma("vm:never-inline")
103+
foo45() => foo46();
104+
@pragma("vm:never-inline")
105+
foo46() => foo47();
106+
@pragma("vm:never-inline")
107+
foo47() => foo48();
108+
@pragma("vm:never-inline")
109+
foo48() => foo49();
110+
@pragma("vm:never-inline")
111+
foo49() => foo50();
112+
@pragma("vm:never-inline")
113+
foo50() => foo51();
114+
@pragma("vm:never-inline")
115+
foo51() => foo52();
116+
@pragma("vm:never-inline")
117+
foo52() => foo53();
118+
@pragma("vm:never-inline")
119+
foo53() => foo54();
120+
@pragma("vm:never-inline")
121+
foo54() => foo55();
122+
@pragma("vm:never-inline")
123+
foo55() => foo56();
124+
@pragma("vm:never-inline")
125+
foo56() => foo57();
126+
@pragma("vm:never-inline")
127+
foo57() => foo58();
128+
@pragma("vm:never-inline")
129+
foo58() => foo59();
130+
@pragma("vm:never-inline")
131+
foo59() => foo60();
132+
@pragma("vm:never-inline")
133+
foo60() => foo61();
134+
@pragma("vm:never-inline")
135+
foo61() => foo62();
136+
@pragma("vm:never-inline")
137+
foo62() => foo63();
138+
@pragma("vm:never-inline")
139+
foo63() => foo64();
140+
141+
int global = 0;
142+
@pragma("vm:never-inline")
143+
foo64() {
144+
for (int i = 0; i < 1000000; i++) {
145+
global = global ^ (global + i);
146+
}
147+
}

runtime/vm/profiler.cc

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -129,19 +129,19 @@ class ProfilerStackWalker : public ValueObject {
129129
public:
130130
ProfilerStackWalker(Dart_Port port_id,
131131
Sample* head_sample,
132-
SampleBuffer* sample_buffer,
132+
Isolate* isolate,
133133
intptr_t skip_count = 0)
134134
: port_id_(port_id),
135135
sample_(head_sample),
136-
sample_buffer_(sample_buffer),
136+
isolate_(isolate),
137137
skip_count_(skip_count),
138138
frames_skipped_(0),
139139
frame_index_(0),
140140
total_frames_(0) {
141141
if (sample_ == nullptr) {
142-
ASSERT(sample_buffer_ == nullptr);
142+
ASSERT(isolate_ == nullptr);
143143
} else {
144-
ASSERT(sample_buffer_ != nullptr);
144+
ASSERT(isolate_ != nullptr);
145145
ASSERT(sample_->head_sample());
146146
}
147147
}
@@ -164,7 +164,7 @@ class ProfilerStackWalker : public ValueObject {
164164
}
165165
ASSERT(sample_ != nullptr);
166166
if (frame_index_ == Sample::kPCArraySizeInWords) {
167-
Sample* new_sample = sample_buffer_->ReserveSampleAndLink(sample_);
167+
Sample* new_sample = SampleBlock::ReserveSampleAndLink(sample_, isolate_);
168168
if (new_sample == nullptr) {
169169
// Could not reserve new sample- mark this as truncated.
170170
sample_->set_truncated_trace(true);
@@ -183,7 +183,7 @@ class ProfilerStackWalker : public ValueObject {
183183
protected:
184184
Dart_Port port_id_;
185185
Sample* sample_;
186-
SampleBuffer* sample_buffer_;
186+
Isolate* isolate_;
187187
intptr_t skip_count_;
188188
intptr_t frames_skipped_;
189189
intptr_t frame_index_;
@@ -245,14 +245,14 @@ class ProfilerNativeStackWalker : public ProfilerStackWalker {
245245
ProfilerNativeStackWalker(ProfilerCounters* counters,
246246
Dart_Port port_id,
247247
Sample* sample,
248-
SampleBuffer* sample_buffer,
248+
Isolate* isolate,
249249
uword stack_lower,
250250
uword stack_upper,
251251
uword pc,
252252
uword fp,
253253
uword sp,
254254
intptr_t skip_count = 0)
255-
: ProfilerStackWalker(port_id, sample, sample_buffer, skip_count),
255+
: ProfilerStackWalker(port_id, sample, isolate, skip_count),
256256
counters_(counters),
257257
stack_upper_(stack_upper),
258258
original_pc_(pc),
@@ -845,10 +845,9 @@ Sample* SampleBlock::ReserveSample() {
845845
return nullptr;
846846
}
847847

848-
Sample* SampleBlock::ReserveSampleAndLink(Sample* previous) {
848+
Sample* SampleBlock::ReserveSampleAndLink(Sample* previous, Isolate* isolate) {
849849
ASSERT(previous != nullptr);
850850
SampleBlockBuffer* buffer = Profiler::sample_block_buffer();
851-
Isolate* isolate = owner_;
852851
ASSERT(isolate != nullptr);
853852
Sample* next = previous->is_allocation_sample()
854853
? buffer->ReserveAllocationSample(isolate)
@@ -1050,20 +1049,16 @@ void ClearProfileVisitor::VisitSample(Sample* sample) {
10501049
class ProfilerDartStackWalker : public ProfilerStackWalker {
10511050
public:
10521051
ProfilerDartStackWalker(Thread* thread,
1052+
Dart_Port port,
10531053
Sample* sample,
1054-
SampleBuffer* sample_buffer,
1054+
Isolate* isolate,
10551055
uword pc,
10561056
uword fp,
10571057
uword sp,
10581058
uword lr,
10591059
bool allocation_sample,
10601060
intptr_t skip_count = 0)
1061-
: ProfilerStackWalker((thread->IGNORE_RACE(isolate)() != nullptr)
1062-
? thread->IGNORE_RACE(isolate)()->main_port()
1063-
: ILLEGAL_PORT,
1064-
sample,
1065-
sample_buffer,
1066-
skip_count),
1061+
: ProfilerStackWalker(port, sample, isolate, skip_count),
10671062
thread_(thread),
10681063
pc_(reinterpret_cast<uword*>(pc)),
10691064
fp_(reinterpret_cast<uword*>(fp)),
@@ -1368,7 +1363,7 @@ void Profiler::SampleAllocation(Thread* thread,
13681363
}
13691364

13701365
Sample* sample =
1371-
SetupSample(thread, /*allocation_block*/ true, os_thread->trace_id());
1366+
SetupSample(thread, /*allocation_sample=*/true, os_thread->trace_id());
13721367
if (sample == nullptr) {
13731368
// We were unable to assign a sample for this allocation.
13741369
counters_.sample_allocation_failure++;
@@ -1377,16 +1372,16 @@ void Profiler::SampleAllocation(Thread* thread,
13771372
sample->SetAllocationCid(cid);
13781373
sample->set_allocation_identity_hash(identity_hash);
13791374

1375+
Dart_Port port = (isolate != nullptr) ? isolate->main_port() : ILLEGAL_PORT;
13801376
if (FLAG_profile_vm_allocation) {
1381-
ProfilerNativeStackWalker native_stack_walker(
1382-
&counters_, (isolate != nullptr) ? isolate->main_port() : ILLEGAL_PORT,
1383-
sample, isolate->current_allocation_sample_block(), stack_lower,
1384-
stack_upper, pc, fp, sp);
1377+
ProfilerNativeStackWalker native_stack_walker(&counters_, port, sample,
1378+
isolate, stack_lower,
1379+
stack_upper, pc, fp, sp);
13851380
native_stack_walker.walk();
13861381
} else if (exited_dart_code) {
1387-
ProfilerDartStackWalker dart_exit_stack_walker(
1388-
thread, sample, isolate->current_allocation_sample_block(), pc, fp, sp,
1389-
lr, /* allocation_sample*/ true);
1382+
ProfilerDartStackWalker dart_exit_stack_walker(thread, port, sample,
1383+
isolate, pc, fp, sp, lr,
1384+
/*allocation_sample=*/true);
13901385
dart_exit_stack_walker.walk();
13911386
} else {
13921387
// Fall back.
@@ -1504,7 +1499,7 @@ void Profiler::SampleThread(Thread* thread,
15041499

15051500
// Setup sample.
15061501
Sample* sample =
1507-
SetupSample(thread, /*allocation_block*/ false, os_thread->trace_id());
1502+
SetupSample(thread, /*allocation_sample=*/false, os_thread->trace_id());
15081503
if (sample == nullptr) {
15091504
// We were unable to assign a sample for this profiler tick.
15101505
counters_.sample_allocation_failure++;
@@ -1543,14 +1538,13 @@ void Profiler::SampleThread(Thread* thread,
15431538
}
15441539
#endif
15451540

1541+
Dart_Port port = (isolate != nullptr) ? isolate->main_port() : ILLEGAL_PORT;
15461542
ProfilerNativeStackWalker native_stack_walker(
1547-
&counters_, (isolate != nullptr) ? isolate->main_port() : ILLEGAL_PORT,
1548-
sample, isolate->current_sample_block(), stack_lower, stack_upper, pc, fp,
1549-
sp);
1543+
&counters_, port, sample, isolate, stack_lower, stack_upper, pc, fp, sp);
15501544
const bool exited_dart_code = thread->IGNORE_RACE2(HasExitedDartCode)();
1551-
ProfilerDartStackWalker dart_stack_walker(
1552-
thread, sample, isolate->current_sample_block(), pc, fp, sp, lr,
1553-
/* allocation_sample*/ false);
1545+
ProfilerDartStackWalker dart_stack_walker(thread, port, sample, isolate, pc,
1546+
fp, sp, lr,
1547+
/*allocation_sample=*/false);
15541548

15551549
// All memory access is done inside CollectSample.
15561550
CollectSample(isolate, exited_dart_code, in_dart_code, sample,
@@ -1768,7 +1762,7 @@ ProcessedSample* SampleBuffer::BuildProcessedSample(
17681762
}
17691763

17701764
if (!sample->exit_frame_sample()) {
1771-
processed_sample->FixupCaller(clt, /* pc_marker */ 0,
1765+
processed_sample->FixupCaller(clt, /*pc_marker=*/0,
17721766
sample->GetStackBuffer());
17731767
}
17741768

runtime/vm/profiler.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -632,9 +632,6 @@ class SampleBuffer {
632632
}
633633
}
634634

635-
virtual Sample* ReserveSample() = 0;
636-
virtual Sample* ReserveSampleAndLink(Sample* previous) = 0;
637-
638635
Sample* At(intptr_t idx) const {
639636
ASSERT(idx >= 0);
640637
ASSERT(idx < capacity_);
@@ -673,8 +670,8 @@ class SampleBlock : public SampleBuffer {
673670
Isolate* owner() const { return owner_; }
674671
void set_owner(Isolate* isolate) { owner_ = isolate; }
675672

676-
virtual Sample* ReserveSample();
677-
virtual Sample* ReserveSampleAndLink(Sample* previous);
673+
Sample* ReserveSample();
674+
static Sample* ReserveSampleAndLink(Sample* previous, Isolate* isolate);
678675

679676
bool TryAllocateFree() {
680677
State expected = kFree;

0 commit comments

Comments
 (0)