Line data Source code
1 : // Copyright 2014 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include <cmath>
6 : #include <limits>
7 :
8 : #include "src/base/platform/platform.h"
9 : #include "src/globals.h"
10 : #include "src/heap/gc-tracer.h"
11 : #include "src/isolate.h"
12 : #include "test/unittests/test-utils.h"
13 : #include "testing/gtest/include/gtest/gtest.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : using GCTracerTest = TestWithContext;
19 :
20 15443 : TEST(GCTracer, AverageSpeed) {
21 : base::RingBuffer<BytesAndDuration> buffer;
22 2 : EXPECT_EQ(100 / 2,
23 0 : GCTracer::AverageSpeed(buffer, MakeBytesAndDuration(100, 2), 0));
24 : buffer.Push(MakeBytesAndDuration(100, 8));
25 2 : EXPECT_EQ(100 / 2,
26 0 : GCTracer::AverageSpeed(buffer, MakeBytesAndDuration(100, 2), 2));
27 2 : EXPECT_EQ(200 / 10,
28 0 : GCTracer::AverageSpeed(buffer, MakeBytesAndDuration(100, 2), 3));
29 1 : const int max_speed = 1024 * MB;
30 : buffer.Reset();
31 : buffer.Push(MakeBytesAndDuration(max_speed, 0.5));
32 2 : EXPECT_EQ(max_speed,
33 0 : GCTracer::AverageSpeed(buffer, MakeBytesAndDuration(0, 0), 1));
34 1 : const int min_speed = 1;
35 : buffer.Reset();
36 : buffer.Push(MakeBytesAndDuration(1, 10000));
37 2 : EXPECT_EQ(min_speed,
38 0 : GCTracer::AverageSpeed(buffer, MakeBytesAndDuration(0, 0), 1));
39 : buffer.Reset();
40 : int sum = 0;
41 11 : for (int i = 0; i < buffer.kSize; i++) {
42 10 : sum += i + 1;
43 10 : buffer.Push(MakeBytesAndDuration(i + 1, 1));
44 : }
45 2 : EXPECT_EQ(
46 : sum * 1.0 / buffer.kSize,
47 0 : GCTracer::AverageSpeed(buffer, MakeBytesAndDuration(0, 0), buffer.kSize));
48 : buffer.Push(MakeBytesAndDuration(100, 1));
49 2 : EXPECT_EQ(
50 : (sum * 1.0 - 1 + 100) / buffer.kSize,
51 0 : GCTracer::AverageSpeed(buffer, MakeBytesAndDuration(0, 0), buffer.kSize));
52 1 : }
53 :
54 : namespace {
55 :
56 : void SampleAndAddAllocaton(v8::internal::GCTracer* tracer, double time_ms,
57 : size_t new_space_counter_bytes,
58 : size_t old_generation_counter_bytes) {
59 : tracer->SampleAllocation(time_ms, new_space_counter_bytes,
60 12 : old_generation_counter_bytes);
61 12 : tracer->AddAllocation(time_ms);
62 : }
63 :
64 : } // namespace
65 :
66 15444 : TEST_F(GCTracerTest, AllocationThroughput) {
67 : GCTracer* tracer = i_isolate()->heap()->tracer();
68 1 : tracer->ResetForTesting();
69 :
70 : int time1 = 100;
71 : size_t counter1 = 1000;
72 : // First sample creates baseline but is not part of the recorded samples.
73 1 : tracer->SampleAllocation(time1, counter1, counter1);
74 : SampleAndAddAllocaton(tracer, time1, counter1, counter1);
75 : int time2 = 200;
76 : size_t counter2 = 2000;
77 : SampleAndAddAllocaton(tracer, time2, counter2, counter2);
78 : // Will only consider the current sample.
79 : size_t throughput = static_cast<size_t>(
80 1 : tracer->AllocationThroughputInBytesPerMillisecond(100));
81 2 : EXPECT_EQ(2 * (counter2 - counter1) / (time2 - time1), throughput);
82 : int time3 = 1000;
83 : size_t counter3 = 30000;
84 : SampleAndAddAllocaton(tracer, time3, counter3, counter3);
85 : // Considers last 2 samples.
86 1 : throughput = tracer->AllocationThroughputInBytesPerMillisecond(801);
87 2 : EXPECT_EQ(2 * (counter3 - counter1) / (time3 - time1), throughput);
88 1 : }
89 :
90 15444 : TEST_F(GCTracerTest, NewSpaceAllocationThroughput) {
91 : GCTracer* tracer = i_isolate()->heap()->tracer();
92 1 : tracer->ResetForTesting();
93 :
94 : int time1 = 100;
95 : size_t counter1 = 1000;
96 : SampleAndAddAllocaton(tracer, time1, counter1, 0);
97 : int time2 = 200;
98 : size_t counter2 = 2000;
99 : SampleAndAddAllocaton(tracer, time2, counter2, 0);
100 : size_t throughput =
101 1 : tracer->NewSpaceAllocationThroughputInBytesPerMillisecond();
102 2 : EXPECT_EQ((counter2 - counter1) / (time2 - time1), throughput);
103 : int time3 = 1000;
104 : size_t counter3 = 30000;
105 : SampleAndAddAllocaton(tracer, time3, counter3, 0);
106 1 : throughput = tracer->NewSpaceAllocationThroughputInBytesPerMillisecond();
107 2 : EXPECT_EQ((counter3 - counter1) / (time3 - time1), throughput);
108 1 : }
109 :
110 15444 : TEST_F(GCTracerTest, NewSpaceAllocationThroughputWithProvidedTime) {
111 : GCTracer* tracer = i_isolate()->heap()->tracer();
112 1 : tracer->ResetForTesting();
113 :
114 : int time1 = 100;
115 : size_t counter1 = 1000;
116 : // First sample creates baseline but is not part of the recorded samples.
117 : SampleAndAddAllocaton(tracer, time1, counter1, 0);
118 : int time2 = 200;
119 : size_t counter2 = 2000;
120 : SampleAndAddAllocaton(tracer, time2, counter2, 0);
121 : // Will only consider the current sample.
122 : size_t throughput =
123 1 : tracer->NewSpaceAllocationThroughputInBytesPerMillisecond(100);
124 2 : EXPECT_EQ((counter2 - counter1) / (time2 - time1), throughput);
125 : int time3 = 1000;
126 : size_t counter3 = 30000;
127 : SampleAndAddAllocaton(tracer, time3, counter3, 0);
128 : // Considers last 2 samples.
129 1 : throughput = tracer->NewSpaceAllocationThroughputInBytesPerMillisecond(801);
130 2 : EXPECT_EQ((counter3 - counter1) / (time3 - time1), throughput);
131 1 : }
132 :
133 15444 : TEST_F(GCTracerTest, OldGenerationAllocationThroughputWithProvidedTime) {
134 : GCTracer* tracer = i_isolate()->heap()->tracer();
135 1 : tracer->ResetForTesting();
136 :
137 : int time1 = 100;
138 : size_t counter1 = 1000;
139 : // First sample creates baseline but is not part of the recorded samples.
140 : SampleAndAddAllocaton(tracer, time1, 0, counter1);
141 : int time2 = 200;
142 : size_t counter2 = 2000;
143 : SampleAndAddAllocaton(tracer, time2, 0, counter2);
144 : // Will only consider the current sample.
145 : size_t throughput = static_cast<size_t>(
146 1 : tracer->OldGenerationAllocationThroughputInBytesPerMillisecond(100));
147 2 : EXPECT_EQ((counter2 - counter1) / (time2 - time1), throughput);
148 : int time3 = 1000;
149 : size_t counter3 = 30000;
150 : SampleAndAddAllocaton(tracer, time3, 0, counter3);
151 : // Considers last 2 samples.
152 : throughput = static_cast<size_t>(
153 1 : tracer->OldGenerationAllocationThroughputInBytesPerMillisecond(801));
154 2 : EXPECT_EQ((counter3 - counter1) / (time3 - time1), throughput);
155 1 : }
156 :
157 15444 : TEST_F(GCTracerTest, RegularScope) {
158 : GCTracer* tracer = i_isolate()->heap()->tracer();
159 1 : tracer->ResetForTesting();
160 :
161 1 : EXPECT_DOUBLE_EQ(0.0, tracer->current_.scopes[GCTracer::Scope::MC_MARK]);
162 : // Sample not added because it's not within a started tracer.
163 : tracer->AddScopeSample(GCTracer::Scope::MC_MARK, 100);
164 : tracer->Start(MARK_COMPACTOR, GarbageCollectionReason::kTesting,
165 1 : "collector unittest");
166 : tracer->AddScopeSample(GCTracer::Scope::MC_MARK, 100);
167 1 : tracer->Stop(MARK_COMPACTOR);
168 1 : EXPECT_DOUBLE_EQ(100.0, tracer->current_.scopes[GCTracer::Scope::MC_MARK]);
169 1 : }
170 :
171 15444 : TEST_F(GCTracerTest, IncrementalScope) {
172 : GCTracer* tracer = i_isolate()->heap()->tracer();
173 1 : tracer->ResetForTesting();
174 :
175 1 : EXPECT_DOUBLE_EQ(
176 0 : 0.0, tracer->current_.scopes[GCTracer::Scope::MC_INCREMENTAL_FINALIZE]);
177 : // Sample is added because its ScopeId is listed as incremental sample.
178 : tracer->AddScopeSample(GCTracer::Scope::MC_INCREMENTAL_FINALIZE, 100);
179 : tracer->Start(MARK_COMPACTOR, GarbageCollectionReason::kTesting,
180 1 : "collector unittest");
181 : // Switch to incremental MC to enable writing back incremental scopes.
182 1 : tracer->current_.type = GCTracer::Event::INCREMENTAL_MARK_COMPACTOR;
183 : tracer->AddScopeSample(GCTracer::Scope::MC_INCREMENTAL_FINALIZE, 100);
184 1 : tracer->Stop(MARK_COMPACTOR);
185 1 : EXPECT_DOUBLE_EQ(
186 0 : 200.0, tracer->current_.scopes[GCTracer::Scope::MC_INCREMENTAL_FINALIZE]);
187 1 : }
188 :
189 15444 : TEST_F(GCTracerTest, IncrementalMarkingDetails) {
190 : GCTracer* tracer = i_isolate()->heap()->tracer();
191 1 : tracer->ResetForTesting();
192 :
193 : // Round 1.
194 : tracer->AddScopeSample(GCTracer::Scope::MC_INCREMENTAL_FINALIZE, 50);
195 : // Scavenger has no impact on incremental marking details.
196 : tracer->Start(SCAVENGER, GarbageCollectionReason::kTesting,
197 1 : "collector unittest");
198 1 : tracer->Stop(SCAVENGER);
199 : tracer->Start(MARK_COMPACTOR, GarbageCollectionReason::kTesting,
200 1 : "collector unittest");
201 : // Switch to incremental MC to enable writing back incremental scopes.
202 1 : tracer->current_.type = GCTracer::Event::INCREMENTAL_MARK_COMPACTOR;
203 : tracer->AddScopeSample(GCTracer::Scope::MC_INCREMENTAL_FINALIZE, 100);
204 1 : tracer->Stop(MARK_COMPACTOR);
205 1 : EXPECT_DOUBLE_EQ(
206 : 100,
207 : tracer->current_
208 : .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_FINALIZE]
209 0 : .longest_step);
210 2 : EXPECT_EQ(
211 : 2,
212 : tracer->current_
213 : .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_FINALIZE]
214 0 : .steps);
215 1 : EXPECT_DOUBLE_EQ(
216 : 150,
217 : tracer->current_
218 : .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_FINALIZE]
219 0 : .duration);
220 :
221 : // Round 2. Numbers should be reset.
222 : tracer->AddScopeSample(GCTracer::Scope::MC_INCREMENTAL_FINALIZE, 13);
223 : tracer->AddScopeSample(GCTracer::Scope::MC_INCREMENTAL_FINALIZE, 15);
224 : tracer->Start(MARK_COMPACTOR, GarbageCollectionReason::kTesting,
225 1 : "collector unittest");
226 : // Switch to incremental MC to enable writing back incremental scopes.
227 1 : tracer->current_.type = GCTracer::Event::INCREMENTAL_MARK_COMPACTOR;
228 : tracer->AddScopeSample(GCTracer::Scope::MC_INCREMENTAL_FINALIZE, 122);
229 1 : tracer->Stop(MARK_COMPACTOR);
230 1 : EXPECT_DOUBLE_EQ(
231 : 122,
232 : tracer->current_
233 : .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_FINALIZE]
234 0 : .longest_step);
235 2 : EXPECT_EQ(
236 : 3,
237 : tracer->current_
238 : .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_FINALIZE]
239 0 : .steps);
240 1 : EXPECT_DOUBLE_EQ(
241 : 150,
242 : tracer->current_
243 : .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_FINALIZE]
244 0 : .duration);
245 1 : }
246 :
247 15444 : TEST_F(GCTracerTest, IncrementalMarkingSpeed) {
248 : GCTracer* tracer = i_isolate()->heap()->tracer();
249 1 : tracer->ResetForTesting();
250 :
251 : // Round 1.
252 : // 1000000 bytes in 100ms.
253 1 : tracer->AddIncrementalMarkingStep(100, 1000000);
254 2 : EXPECT_EQ(1000000 / 100,
255 0 : tracer->IncrementalMarkingSpeedInBytesPerMillisecond());
256 : // 1000000 bytes in 100ms.
257 1 : tracer->AddIncrementalMarkingStep(100, 1000000);
258 2 : EXPECT_EQ(1000000 / 100,
259 0 : tracer->IncrementalMarkingSpeedInBytesPerMillisecond());
260 : // Scavenger has no impact on incremental marking details.
261 : tracer->Start(SCAVENGER, GarbageCollectionReason::kTesting,
262 1 : "collector unittest");
263 1 : tracer->Stop(SCAVENGER);
264 : // 1000000 bytes in 100ms.
265 1 : tracer->AddIncrementalMarkingStep(100, 1000000);
266 2 : EXPECT_EQ(300, tracer->incremental_marking_duration_);
267 2 : EXPECT_EQ(3000000u, tracer->incremental_marking_bytes_);
268 2 : EXPECT_EQ(1000000 / 100,
269 0 : tracer->IncrementalMarkingSpeedInBytesPerMillisecond());
270 : tracer->Start(MARK_COMPACTOR, GarbageCollectionReason::kTesting,
271 1 : "collector unittest");
272 : // Switch to incremental MC.
273 1 : tracer->current_.type = GCTracer::Event::INCREMENTAL_MARK_COMPACTOR;
274 : // 1000000 bytes in 100ms.
275 1 : tracer->AddIncrementalMarkingStep(100, 1000000);
276 2 : EXPECT_EQ(400, tracer->incremental_marking_duration_);
277 2 : EXPECT_EQ(4000000u, tracer->incremental_marking_bytes_);
278 1 : tracer->Stop(MARK_COMPACTOR);
279 2 : EXPECT_EQ(400, tracer->current_.incremental_marking_duration);
280 2 : EXPECT_EQ(4000000u, tracer->current_.incremental_marking_bytes);
281 2 : EXPECT_EQ(0, tracer->incremental_marking_duration_);
282 2 : EXPECT_EQ(0u, tracer->incremental_marking_bytes_);
283 2 : EXPECT_EQ(1000000 / 100,
284 0 : tracer->IncrementalMarkingSpeedInBytesPerMillisecond());
285 :
286 : // Round 2.
287 1 : tracer->AddIncrementalMarkingStep(2000, 1000);
288 : tracer->Start(MARK_COMPACTOR, GarbageCollectionReason::kTesting,
289 1 : "collector unittest");
290 : // Switch to incremental MC.
291 1 : tracer->current_.type = GCTracer::Event::INCREMENTAL_MARK_COMPACTOR;
292 1 : tracer->Stop(MARK_COMPACTOR);
293 1 : EXPECT_DOUBLE_EQ((4000000.0 / 400 + 1000.0 / 2000) / 2,
294 : static_cast<double>(
295 0 : tracer->IncrementalMarkingSpeedInBytesPerMillisecond()));
296 1 : }
297 :
298 15444 : TEST_F(GCTracerTest, MutatorUtilization) {
299 : GCTracer* tracer = i_isolate()->heap()->tracer();
300 1 : tracer->ResetForTesting();
301 :
302 : // Mark-compact #1 ended at 200ms and took 100ms.
303 1 : tracer->RecordMutatorUtilization(200, 100);
304 : // Avarage mark-compact time = 0ms.
305 : // Avarage mutator time = 0ms.
306 1 : EXPECT_DOUBLE_EQ(1.0, tracer->CurrentMarkCompactMutatorUtilization());
307 1 : EXPECT_DOUBLE_EQ(1.0, tracer->AverageMarkCompactMutatorUtilization());
308 :
309 : // Mark-compact #2 ended at 400ms and took 100ms.
310 1 : tracer->RecordMutatorUtilization(400, 100);
311 : // The first mark-compactor is ignored.
312 : // Avarage mark-compact time = 100ms.
313 : // Avarage mutator time = 100ms.
314 1 : EXPECT_DOUBLE_EQ(0.5, tracer->CurrentMarkCompactMutatorUtilization());
315 1 : EXPECT_DOUBLE_EQ(0.5, tracer->AverageMarkCompactMutatorUtilization());
316 :
317 : // Mark-compact #3 ended at 600ms and took 200ms.
318 1 : tracer->RecordMutatorUtilization(600, 200);
319 : // Avarage mark-compact time = 100ms * 0.5 + 200ms * 0.5.
320 : // Avarage mutator time = 100ms * 0.5 + 0ms * 0.5.
321 1 : EXPECT_DOUBLE_EQ(0.0, tracer->CurrentMarkCompactMutatorUtilization());
322 1 : EXPECT_DOUBLE_EQ(50.0 / 200.0,
323 0 : tracer->AverageMarkCompactMutatorUtilization());
324 :
325 : // Mark-compact #4 ended at 800ms and took 0ms.
326 1 : tracer->RecordMutatorUtilization(800, 0);
327 : // Avarage mark-compact time = 150ms * 0.5 + 0ms * 0.5.
328 : // Avarage mutator time = 50ms * 0.5 + 200ms * 0.5.
329 1 : EXPECT_DOUBLE_EQ(1.0, tracer->CurrentMarkCompactMutatorUtilization());
330 1 : EXPECT_DOUBLE_EQ(125.0 / 200.0,
331 0 : tracer->AverageMarkCompactMutatorUtilization());
332 1 : }
333 :
334 15444 : TEST_F(GCTracerTest, BackgroundScavengerScope) {
335 : GCTracer* tracer = i_isolate()->heap()->tracer();
336 1 : tracer->ResetForTesting();
337 : tracer->Start(SCAVENGER, GarbageCollectionReason::kTesting,
338 1 : "collector unittest");
339 : tracer->AddBackgroundScopeSample(
340 : GCTracer::BackgroundScope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL, 10,
341 1 : nullptr);
342 : tracer->AddBackgroundScopeSample(
343 : GCTracer::BackgroundScope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL, 1,
344 1 : nullptr);
345 1 : tracer->Stop(SCAVENGER);
346 1 : EXPECT_DOUBLE_EQ(
347 : 11, tracer->current_
348 0 : .scopes[GCTracer::Scope::SCAVENGER_BACKGROUND_SCAVENGE_PARALLEL]);
349 1 : }
350 :
351 15444 : TEST_F(GCTracerTest, BackgroundMinorMCScope) {
352 : GCTracer* tracer = i_isolate()->heap()->tracer();
353 1 : tracer->ResetForTesting();
354 : tracer->Start(MINOR_MARK_COMPACTOR, GarbageCollectionReason::kTesting,
355 1 : "collector unittest");
356 : tracer->AddBackgroundScopeSample(
357 1 : GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_MARKING, 10, nullptr);
358 : tracer->AddBackgroundScopeSample(
359 1 : GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_MARKING, 1, nullptr);
360 : tracer->AddBackgroundScopeSample(
361 : GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_EVACUATE_COPY, 20,
362 1 : nullptr);
363 : tracer->AddBackgroundScopeSample(
364 1 : GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_EVACUATE_COPY, 2, nullptr);
365 : tracer->AddBackgroundScopeSample(
366 : GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_EVACUATE_UPDATE_POINTERS,
367 1 : 30, nullptr);
368 : tracer->AddBackgroundScopeSample(
369 : GCTracer::BackgroundScope::MINOR_MC_BACKGROUND_EVACUATE_UPDATE_POINTERS,
370 1 : 3, nullptr);
371 1 : tracer->Stop(MINOR_MARK_COMPACTOR);
372 1 : EXPECT_DOUBLE_EQ(
373 : 11,
374 0 : tracer->current_.scopes[GCTracer::Scope::MINOR_MC_BACKGROUND_MARKING]);
375 1 : EXPECT_DOUBLE_EQ(
376 : 22, tracer->current_
377 0 : .scopes[GCTracer::Scope::MINOR_MC_BACKGROUND_EVACUATE_COPY]);
378 1 : EXPECT_DOUBLE_EQ(
379 : 33, tracer->current_.scopes
380 0 : [GCTracer::Scope::MINOR_MC_BACKGROUND_EVACUATE_UPDATE_POINTERS]);
381 1 : }
382 :
383 15444 : TEST_F(GCTracerTest, BackgroundMajorMCScope) {
384 : GCTracer* tracer = i_isolate()->heap()->tracer();
385 1 : tracer->ResetForTesting();
386 : tracer->AddBackgroundScopeSample(
387 1 : GCTracer::BackgroundScope::MC_BACKGROUND_MARKING, 100, nullptr);
388 : tracer->AddBackgroundScopeSample(
389 1 : GCTracer::BackgroundScope::MC_BACKGROUND_SWEEPING, 200, nullptr);
390 : tracer->AddBackgroundScopeSample(
391 1 : GCTracer::BackgroundScope::MC_BACKGROUND_MARKING, 10, nullptr);
392 : // Scavenger should not affect the major mark-compact scopes.
393 : tracer->Start(SCAVENGER, GarbageCollectionReason::kTesting,
394 1 : "collector unittest");
395 1 : tracer->Stop(SCAVENGER);
396 : tracer->AddBackgroundScopeSample(
397 1 : GCTracer::BackgroundScope::MC_BACKGROUND_SWEEPING, 20, nullptr);
398 : tracer->AddBackgroundScopeSample(
399 1 : GCTracer::BackgroundScope::MC_BACKGROUND_MARKING, 1, nullptr);
400 : tracer->AddBackgroundScopeSample(
401 1 : GCTracer::BackgroundScope::MC_BACKGROUND_SWEEPING, 2, nullptr);
402 : tracer->Start(MARK_COMPACTOR, GarbageCollectionReason::kTesting,
403 1 : "collector unittest");
404 : tracer->AddBackgroundScopeSample(
405 1 : GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_COPY, 30, nullptr);
406 : tracer->AddBackgroundScopeSample(
407 1 : GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_COPY, 3, nullptr);
408 : tracer->AddBackgroundScopeSample(
409 : GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_UPDATE_POINTERS, 40,
410 1 : nullptr);
411 : tracer->AddBackgroundScopeSample(
412 : GCTracer::BackgroundScope::MC_BACKGROUND_EVACUATE_UPDATE_POINTERS, 4,
413 1 : nullptr);
414 1 : tracer->Stop(MARK_COMPACTOR);
415 1 : EXPECT_DOUBLE_EQ(
416 0 : 111, tracer->current_.scopes[GCTracer::Scope::MC_BACKGROUND_MARKING]);
417 1 : EXPECT_DOUBLE_EQ(
418 0 : 222, tracer->current_.scopes[GCTracer::Scope::MC_BACKGROUND_SWEEPING]);
419 1 : EXPECT_DOUBLE_EQ(
420 : 33,
421 0 : tracer->current_.scopes[GCTracer::Scope::MC_BACKGROUND_EVACUATE_COPY]);
422 1 : EXPECT_DOUBLE_EQ(
423 : 44, tracer->current_
424 0 : .scopes[GCTracer::Scope::MC_BACKGROUND_EVACUATE_UPDATE_POINTERS]);
425 1 : }
426 :
427 1 : class ThreadWithBackgroundScope final : public base::Thread {
428 : public:
429 : explicit ThreadWithBackgroundScope(GCTracer* tracer)
430 2 : : Thread(Options("ThreadWithBackgroundScope")), tracer_(tracer) {}
431 2 : void Run() override {
432 : GCTracer::BackgroundScope scope(
433 2 : tracer_, GCTracer::BackgroundScope::MC_BACKGROUND_MARKING);
434 2 : }
435 :
436 : private:
437 : GCTracer* tracer_;
438 : };
439 :
440 15444 : TEST_F(GCTracerTest, MultithreadedBackgroundScope) {
441 : GCTracer* tracer = i_isolate()->heap()->tracer();
442 : ThreadWithBackgroundScope thread1(tracer);
443 : ThreadWithBackgroundScope thread2(tracer);
444 1 : tracer->ResetForTesting();
445 1 : thread1.Start();
446 1 : thread2.Start();
447 1 : tracer->FetchBackgroundMarkCompactCounters();
448 1 : thread1.Join();
449 1 : thread2.Join();
450 1 : tracer->FetchBackgroundMarkCompactCounters();
451 1 : EXPECT_LE(0, tracer->current_.scopes[GCTracer::Scope::MC_BACKGROUND_MARKING]);
452 1 : }
453 :
454 354 : class GcHistogram {
455 : public:
456 354 : static void* CreateHistogram(const char* name, int min, int max,
457 : size_t buckets) {
458 708 : histograms_[name] = std::unique_ptr<GcHistogram>(new GcHistogram());
459 708 : return histograms_[name].get();
460 : }
461 :
462 11 : static void AddHistogramSample(void* histogram, int sample) {
463 11 : if (histograms_.empty()) return;
464 11 : static_cast<GcHistogram*>(histogram)->samples_.push_back(sample);
465 : }
466 :
467 20 : static GcHistogram* Get(const char* name) { return histograms_[name].get(); }
468 :
469 : static void CleanUp() { histograms_.clear(); }
470 :
471 : int Total() const {
472 : int result = 0;
473 20 : for (int i : samples_) {
474 10 : result += i;
475 : }
476 : return result;
477 : }
478 :
479 : int Count() const { return static_cast<int>(samples_.size()); }
480 :
481 : private:
482 : std::vector<int> samples_;
483 : static std::map<std::string, std::unique_ptr<GcHistogram>> histograms_;
484 : };
485 :
486 3088 : std::map<std::string, std::unique_ptr<GcHistogram>> GcHistogram::histograms_ =
487 : std::map<std::string, std::unique_ptr<GcHistogram>>();
488 :
489 15444 : TEST_F(GCTracerTest, RecordMarkCompactHistograms) {
490 1 : if (FLAG_stress_incremental_marking) return;
491 1 : isolate()->SetCreateHistogramFunction(&GcHistogram::CreateHistogram);
492 1 : isolate()->SetAddHistogramSampleFunction(&GcHistogram::AddHistogramSample);
493 : GCTracer* tracer = i_isolate()->heap()->tracer();
494 1 : tracer->ResetForTesting();
495 1 : tracer->current_.scopes[GCTracer::Scope::MC_CLEAR] = 1;
496 1 : tracer->current_.scopes[GCTracer::Scope::MC_EPILOGUE] = 2;
497 1 : tracer->current_.scopes[GCTracer::Scope::MC_EVACUATE] = 3;
498 1 : tracer->current_.scopes[GCTracer::Scope::MC_FINISH] = 4;
499 1 : tracer->current_.scopes[GCTracer::Scope::MC_MARK] = 5;
500 1 : tracer->current_.scopes[GCTracer::Scope::MC_PROLOGUE] = 6;
501 1 : tracer->current_.scopes[GCTracer::Scope::MC_SWEEP] = 7;
502 1 : tracer->RecordGCPhasesHistograms(i_isolate()->counters()->gc_finalize());
503 3 : EXPECT_EQ(1, GcHistogram::Get("V8.GCFinalizeMC.Clear")->Total());
504 3 : EXPECT_EQ(2, GcHistogram::Get("V8.GCFinalizeMC.Epilogue")->Total());
505 3 : EXPECT_EQ(3, GcHistogram::Get("V8.GCFinalizeMC.Evacuate")->Total());
506 3 : EXPECT_EQ(4, GcHistogram::Get("V8.GCFinalizeMC.Finish")->Total());
507 3 : EXPECT_EQ(5, GcHistogram::Get("V8.GCFinalizeMC.Mark")->Total());
508 3 : EXPECT_EQ(6, GcHistogram::Get("V8.GCFinalizeMC.Prologue")->Total());
509 3 : EXPECT_EQ(7, GcHistogram::Get("V8.GCFinalizeMC.Sweep")->Total());
510 : GcHistogram::CleanUp();
511 : }
512 :
513 15444 : TEST_F(GCTracerTest, RecordScavengerHistograms) {
514 1 : if (FLAG_stress_incremental_marking) return;
515 1 : isolate()->SetCreateHistogramFunction(&GcHistogram::CreateHistogram);
516 1 : isolate()->SetAddHistogramSampleFunction(&GcHistogram::AddHistogramSample);
517 : GCTracer* tracer = i_isolate()->heap()->tracer();
518 1 : tracer->ResetForTesting();
519 1 : tracer->current_.scopes[GCTracer::Scope::SCAVENGER_SCAVENGE_ROOTS] = 1;
520 1 : tracer->current_.scopes[GCTracer::Scope::SCAVENGER_SCAVENGE_PARALLEL] = 2;
521 1 : tracer->RecordGCPhasesHistograms(i_isolate()->counters()->gc_scavenger());
522 3 : EXPECT_EQ(1, GcHistogram::Get("V8.GCScavenger.ScavengeRoots")->Total());
523 3 : EXPECT_EQ(2, GcHistogram::Get("V8.GCScavenger.ScavengeMain")->Total());
524 : GcHistogram::CleanUp();
525 : }
526 :
527 15444 : TEST_F(GCTracerTest, RecordGCSumHistograms) {
528 1 : if (FLAG_stress_incremental_marking) return;
529 1 : isolate()->SetCreateHistogramFunction(&GcHistogram::CreateHistogram);
530 1 : isolate()->SetAddHistogramSampleFunction(&GcHistogram::AddHistogramSample);
531 : GCTracer* tracer = i_isolate()->heap()->tracer();
532 1 : tracer->ResetForTesting();
533 : tracer->current_
534 : .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_START]
535 1 : .duration = 1;
536 : tracer->current_
537 : .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_SWEEPING]
538 1 : .duration = 2;
539 1 : tracer->AddIncrementalMarkingStep(3.0, 1024);
540 : tracer->current_
541 : .incremental_marking_scopes[GCTracer::Scope::MC_INCREMENTAL_FINALIZE]
542 1 : .duration = 4;
543 : const double atomic_pause_duration = 5.0;
544 1 : tracer->RecordGCSumCounters(atomic_pause_duration);
545 3 : EXPECT_EQ(15, GcHistogram::Get("V8.GCMarkCompactor")->Total());
546 : GcHistogram::CleanUp();
547 : }
548 :
549 : } // namespace internal
550 9264 : } // namespace v8
|