1 // Copyright 2015 The Chromium Authors
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 "base/profiler/stack_sampling_profiler.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <cstdlib>
11 #include <memory>
12 #include <set>
13 #include <utility>
14 #include <vector>
15
16 #include "base/compiler_specific.h"
17 #include "base/files/file_util.h"
18 #include "base/functional/bind.h"
19 #include "base/functional/callback.h"
20 #include "base/location.h"
21 #include "base/memory/ptr_util.h"
22 #include "base/memory/raw_ptr.h"
23 #include "base/metrics/metrics_hashes.h"
24 #include "base/notimplemented.h"
25 #include "base/profiler/profiler_buildflags.h"
26 #include "base/profiler/sample_metadata.h"
27 #include "base/profiler/stack_sampler.h"
28 #include "base/profiler/stack_sampling_profiler_test_util.h"
29 #include "base/profiler/unwinder.h"
30 #include "base/ranges/algorithm.h"
31 #include "base/run_loop.h"
32 #include "base/scoped_native_library.h"
33 #include "base/strings/utf_string_conversions.h"
34 #include "base/synchronization/lock.h"
35 #include "base/synchronization/waitable_event.h"
36 #include "base/test/bind.h"
37 #include "base/test/task_environment.h"
38 #include "base/threading/simple_thread.h"
39 #include "base/time/time.h"
40 #include "build/build_config.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42
43 #if BUILDFLAG(IS_WIN)
44 #include <windows.h>
45
46 #include <intrin.h>
47 #include <malloc.h>
48 #else
49 #include <alloca.h>
50 #endif
51
52 // STACK_SAMPLING_PROFILER_SUPPORTED is used to conditionally enable the tests
53 // below for supported platforms (currently Win x64, Mac, iOS 64, some
54 // Android, and ChromeOS x64).
55 // ChromeOS: These don't run under MSan because parts of the stack aren't
56 // initialized.
57 #if (BUILDFLAG(IS_WIN) && defined(ARCH_CPU_X86_64)) || (BUILDFLAG(IS_MAC)) || \
58 (BUILDFLAG(IS_IOS) && defined(ARCH_CPU_64_BITS)) || \
59 (BUILDFLAG(IS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)) || \
60 (BUILDFLAG(IS_CHROMEOS) && \
61 (defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_ARM64)) && \
62 !defined(MEMORY_SANITIZER))
63 #define STACK_SAMPLING_PROFILER_SUPPORTED 1
64 #endif
65
66 namespace base {
67
68 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
69 #define PROFILER_TEST_F(TestClass, TestName) TEST_F(TestClass, TestName)
70 #else
71 #define PROFILER_TEST_F(TestClass, TestName) \
72 TEST_F(TestClass, DISABLED_##TestName)
73 #endif
74
75 using SamplingParams = StackSamplingProfiler::SamplingParams;
76
77 namespace {
78
79 // State provided to the ProfileBuilder's ApplyMetadataRetrospectively function.
80 struct RetrospectiveMetadata {
81 TimeTicks period_start;
82 TimeTicks period_end;
83 MetadataRecorder::Item item;
84 };
85
86 // Profile consists of a set of samples and other sampling information.
87 struct Profile {
88 // The collected samples.
89 std::vector<std::vector<Frame>> samples;
90
91 // The number of invocations of RecordMetadata().
92 int record_metadata_count;
93
94 // The retrospective metadata requests.
95 std::vector<RetrospectiveMetadata> retrospective_metadata;
96
97 // The profile metadata requests.
98 std::vector<MetadataRecorder::Item> profile_metadata;
99
100 // Duration of this profile.
101 TimeDelta profile_duration;
102
103 // Time between samples.
104 TimeDelta sampling_period;
105 };
106
107 // The callback type used to collect a profile. The passed Profile is move-only.
108 // Other threads, including the UI thread, may block on callback completion so
109 // this should run as quickly as possible.
110 using ProfileCompletedCallback = OnceCallback<void(Profile)>;
111
112 // TestProfileBuilder collects samples produced by the profiler.
113 class TestProfileBuilder : public ProfileBuilder {
114 public:
115 TestProfileBuilder(ModuleCache* module_cache,
116 ProfileCompletedCallback callback);
117
118 TestProfileBuilder(const TestProfileBuilder&) = delete;
119 TestProfileBuilder& operator=(const TestProfileBuilder&) = delete;
120
121 ~TestProfileBuilder() override;
122
123 // ProfileBuilder:
124 ModuleCache* GetModuleCache() override;
125 void RecordMetadata(
126 const MetadataRecorder::MetadataProvider& metadata_provider) override;
127 void ApplyMetadataRetrospectively(
128 TimeTicks period_start,
129 TimeTicks period_end,
130 const MetadataRecorder::Item& item) override;
131 void AddProfileMetadata(const MetadataRecorder::Item& item) override;
132 void OnSampleCompleted(std::vector<Frame> sample,
133 TimeTicks sample_timestamp) override;
134 void OnProfileCompleted(TimeDelta profile_duration,
135 TimeDelta sampling_period) override;
136
137 private:
138 raw_ptr<ModuleCache> module_cache_;
139
140 // The set of recorded samples.
141 std::vector<std::vector<Frame>> samples_;
142
143 // The number of invocations of RecordMetadata().
144 int record_metadata_count_ = 0;
145
146 // The retrospective metadata requests.
147 std::vector<RetrospectiveMetadata> retrospective_metadata_;
148
149 // The profile metadata requests.
150 std::vector<MetadataRecorder::Item> profile_metadata_;
151
152 // Callback made when sampling a profile completes.
153 ProfileCompletedCallback callback_;
154 };
155
TestProfileBuilder(ModuleCache * module_cache,ProfileCompletedCallback callback)156 TestProfileBuilder::TestProfileBuilder(ModuleCache* module_cache,
157 ProfileCompletedCallback callback)
158 : module_cache_(module_cache), callback_(std::move(callback)) {}
159
160 TestProfileBuilder::~TestProfileBuilder() = default;
161
GetModuleCache()162 ModuleCache* TestProfileBuilder::GetModuleCache() {
163 return module_cache_;
164 }
165
RecordMetadata(const MetadataRecorder::MetadataProvider & metadata_provider)166 void TestProfileBuilder::RecordMetadata(
167 const MetadataRecorder::MetadataProvider& metadata_provider) {
168 ++record_metadata_count_;
169 }
170
ApplyMetadataRetrospectively(TimeTicks period_start,TimeTicks period_end,const MetadataRecorder::Item & item)171 void TestProfileBuilder::ApplyMetadataRetrospectively(
172 TimeTicks period_start,
173 TimeTicks period_end,
174 const MetadataRecorder::Item& item) {
175 retrospective_metadata_.push_back(
176 RetrospectiveMetadata{period_start, period_end, item});
177 }
178
AddProfileMetadata(const MetadataRecorder::Item & item)179 void TestProfileBuilder::AddProfileMetadata(
180 const MetadataRecorder::Item& item) {
181 profile_metadata_.push_back(item);
182 }
183
OnSampleCompleted(std::vector<Frame> sample,TimeTicks sample_timestamp)184 void TestProfileBuilder::OnSampleCompleted(std::vector<Frame> sample,
185 TimeTicks sample_timestamp) {
186 samples_.push_back(std::move(sample));
187 }
188
OnProfileCompleted(TimeDelta profile_duration,TimeDelta sampling_period)189 void TestProfileBuilder::OnProfileCompleted(TimeDelta profile_duration,
190 TimeDelta sampling_period) {
191 std::move(callback_).Run(Profile{samples_, record_metadata_count_,
192 retrospective_metadata_, profile_metadata_,
193 profile_duration, sampling_period});
194 }
195
196 // Unloads |library| and returns when it has completed unloading. Unloading a
197 // library is asynchronous on Windows, so simply calling UnloadNativeLibrary()
198 // is insufficient to ensure it's been unloaded.
SynchronousUnloadNativeLibrary(NativeLibrary library)199 void SynchronousUnloadNativeLibrary(NativeLibrary library) {
200 UnloadNativeLibrary(library);
201 #if BUILDFLAG(IS_WIN)
202 // NativeLibrary is a typedef for HMODULE, which is actually the base address
203 // of the module.
204 uintptr_t module_base_address = reinterpret_cast<uintptr_t>(library);
205 HMODULE module_handle;
206 // Keep trying to get the module handle until the call fails.
207 while (::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
208 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
209 reinterpret_cast<LPCTSTR>(module_base_address),
210 &module_handle) ||
211 ::GetLastError() != ERROR_MOD_NOT_FOUND) {
212 PlatformThread::Sleep(Milliseconds(1));
213 }
214 #elif BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
215 // Unloading a library on Mac and Android is synchronous.
216 #else
217 NOTIMPLEMENTED();
218 #endif
219 }
220
WithTargetThread(ProfileCallback profile_callback)221 void WithTargetThread(ProfileCallback profile_callback) {
222 UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
223 WithTargetThread(&scenario, std::move(profile_callback));
224 }
225
226 struct TestProfilerInfo {
TestProfilerInfobase::__anon89fa5ca80111::TestProfilerInfo227 TestProfilerInfo(SamplingProfilerThreadToken thread_token,
228 const SamplingParams& params,
229 ModuleCache* module_cache,
230 StackSamplerTestDelegate* delegate = nullptr)
231 : completed(WaitableEvent::ResetPolicy::MANUAL,
232 WaitableEvent::InitialState::NOT_SIGNALED),
233 profiler(thread_token,
234 params,
235 std::make_unique<TestProfileBuilder>(
236 module_cache,
237 BindLambdaForTesting([this](Profile result_profile) {
238 profile = std::move(result_profile);
239 completed.Signal();
240 })),
241 CreateCoreUnwindersFactoryForTesting(module_cache),
242 RepeatingClosure(),
243 delegate) {}
244
245 TestProfilerInfo(const TestProfilerInfo&) = delete;
246 TestProfilerInfo& operator=(const TestProfilerInfo&) = delete;
247
248 // The order here is important to ensure objects being referenced don't get
249 // destructed until after the objects referencing them.
250 Profile profile;
251 WaitableEvent completed;
252 StackSamplingProfiler profiler;
253 };
254
255 // Captures samples as specified by |params| on the TargetThread, and returns
256 // them. Waits up to |profiler_wait_time| for the profiler to complete.
CaptureSamples(const SamplingParams & params,TimeDelta profiler_wait_time,ModuleCache * module_cache)257 std::vector<std::vector<Frame>> CaptureSamples(const SamplingParams& params,
258 TimeDelta profiler_wait_time,
259 ModuleCache* module_cache) {
260 std::vector<std::vector<Frame>> samples;
261 WithTargetThread(BindLambdaForTesting(
262 [&](SamplingProfilerThreadToken target_thread_token) {
263 TestProfilerInfo info(target_thread_token, params, module_cache);
264 info.profiler.Start();
265 info.completed.TimedWait(profiler_wait_time);
266 info.profiler.Stop();
267 info.completed.Wait();
268 samples = std::move(info.profile.samples);
269 }));
270
271 return samples;
272 }
273
274 // Waits for one of multiple samplings to complete.
WaitForSamplingComplete(const std::vector<std::unique_ptr<TestProfilerInfo>> & infos)275 size_t WaitForSamplingComplete(
276 const std::vector<std::unique_ptr<TestProfilerInfo>>& infos) {
277 // Map unique_ptrs to something that WaitMany can accept.
278 std::vector<WaitableEvent*> sampling_completed_rawptrs(infos.size());
279 ranges::transform(infos, sampling_completed_rawptrs.begin(),
280 [](const std::unique_ptr<TestProfilerInfo>& info) {
281 return &info.get()->completed;
282 });
283 // Wait for one profiler to finish.
284 return WaitableEvent::WaitMany(sampling_completed_rawptrs.data(),
285 sampling_completed_rawptrs.size());
286 }
287
288 // Returns a duration that is longer than the test timeout. We would use
289 // TimeDelta::Max() but https://crbug.com/465948.
AVeryLongTimeDelta()290 TimeDelta AVeryLongTimeDelta() {
291 return Days(1);
292 }
293
294 // Tests the scenario where the library is unloaded after copying the stack, but
295 // before walking it. If |wait_until_unloaded| is true, ensures that the
296 // asynchronous library loading has completed before walking the stack. If
297 // false, the unloading may still be occurring during the stack walk.
TestLibraryUnload(bool wait_until_unloaded,ModuleCache * module_cache)298 void TestLibraryUnload(bool wait_until_unloaded, ModuleCache* module_cache) {
299 // Test delegate that supports intervening between the copying of the stack
300 // and the walking of the stack.
301 class StackCopiedSignaler : public StackSamplerTestDelegate {
302 public:
303 StackCopiedSignaler(WaitableEvent* stack_copied,
304 WaitableEvent* start_stack_walk,
305 bool wait_to_walk_stack)
306 : stack_copied_(stack_copied),
307 start_stack_walk_(start_stack_walk),
308 wait_to_walk_stack_(wait_to_walk_stack) {}
309
310 void OnPreStackWalk() override {
311 stack_copied_->Signal();
312 if (wait_to_walk_stack_)
313 start_stack_walk_->Wait();
314 }
315
316 private:
317 const raw_ptr<WaitableEvent> stack_copied_;
318 const raw_ptr<WaitableEvent> start_stack_walk_;
319 const bool wait_to_walk_stack_;
320 };
321
322 SamplingParams params;
323 params.sampling_interval = Milliseconds(0);
324 params.samples_per_profile = 1;
325
326 NativeLibrary other_library = LoadOtherLibrary();
327
328 // TODO(crbug.com/40061562): Remove `UnsafeDanglingUntriaged`
329 UnwindScenario scenario(BindRepeating(
330 &CallThroughOtherLibrary, UnsafeDanglingUntriaged(other_library)));
331
332 UnwindScenario::SampleEvents events;
333 TargetThread target_thread(
334 BindLambdaForTesting([&] { scenario.Execute(&events); }));
335 target_thread.Start();
336 events.ready_for_sample.Wait();
337
338 WaitableEvent sampling_thread_completed(
339 WaitableEvent::ResetPolicy::MANUAL,
340 WaitableEvent::InitialState::NOT_SIGNALED);
341 Profile profile;
342
343 WaitableEvent stack_copied(WaitableEvent::ResetPolicy::MANUAL,
344 WaitableEvent::InitialState::NOT_SIGNALED);
345 WaitableEvent start_stack_walk(WaitableEvent::ResetPolicy::MANUAL,
346 WaitableEvent::InitialState::NOT_SIGNALED);
347 StackCopiedSignaler test_delegate(&stack_copied, &start_stack_walk,
348 wait_until_unloaded);
349 StackSamplingProfiler profiler(
350 target_thread.thread_token(), params,
351 std::make_unique<TestProfileBuilder>(
352 module_cache,
353 BindLambdaForTesting(
354 [&profile, &sampling_thread_completed](Profile result_profile) {
355 profile = std::move(result_profile);
356 sampling_thread_completed.Signal();
357 })),
358 CreateCoreUnwindersFactoryForTesting(module_cache), RepeatingClosure(),
359 &test_delegate);
360
361 profiler.Start();
362
363 // Wait for the stack to be copied and the target thread to be resumed.
364 stack_copied.Wait();
365
366 // Cause the target thread to finish, so that it's no longer executing code in
367 // the library we're about to unload.
368 events.sample_finished.Signal();
369 target_thread.Join();
370
371 // Unload the library now that it's not being used.
372 if (wait_until_unloaded)
373 SynchronousUnloadNativeLibrary(other_library);
374 else
375 UnloadNativeLibrary(other_library);
376
377 // Let the stack walk commence after unloading the library, if we're waiting
378 // on that event.
379 start_stack_walk.Signal();
380
381 // Wait for the sampling thread to complete and fill out |profile|.
382 sampling_thread_completed.Wait();
383
384 // Look up the sample.
385 ASSERT_EQ(1u, profile.samples.size());
386 const std::vector<Frame>& sample = profile.samples[0];
387
388 if (wait_until_unloaded) {
389 // We expect the stack to look something like this, with the frame in the
390 // now-unloaded library having a null module.
391 //
392 // ... WaitableEvent and system frames ...
393 // WaitForSample()
394 // TargetThread::OtherLibraryCallback
395 // <frame in unloaded library>
396 EXPECT_EQ(nullptr, sample.back().module)
397 << "Stack:\n"
398 << FormatSampleForDiagnosticOutput(sample);
399
400 ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange()});
401 ExpectStackDoesNotContain(sample,
402 {scenario.GetSetupFunctionAddressRange(),
403 scenario.GetOuterFunctionAddressRange()});
404 } else {
405 // We didn't wait for the asynchronous unloading to complete, so the results
406 // are non-deterministic: if the library finished unloading we should have
407 // the same stack as |wait_until_unloaded|, if not we should have the full
408 // stack. The important thing is that we should not crash.
409
410 if (!sample.back().module) {
411 // This is the same case as |wait_until_unloaded|.
412 ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange()});
413 ExpectStackDoesNotContain(sample,
414 {scenario.GetSetupFunctionAddressRange(),
415 scenario.GetOuterFunctionAddressRange()});
416 return;
417 }
418
419 ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
420 scenario.GetSetupFunctionAddressRange(),
421 scenario.GetOuterFunctionAddressRange()});
422 }
423 }
424
425 // Provide a suitable (and clean) environment for the tests below. All tests
426 // must use this class to ensure that proper clean-up is done and thus be
427 // usable in a later test.
428 class StackSamplingProfilerTest : public testing::Test {
429 public:
430 StackSamplingProfilerTest() = default;
431
SetUp()432 void SetUp() override {
433 // The idle-shutdown time is too long for convenient (and accurate) testing.
434 // That behavior is checked instead by artificially triggering it through
435 // the TestPeer.
436 StackSamplingProfiler::TestPeer::DisableIdleShutdown();
437 }
438
TearDown()439 void TearDown() override {
440 // Be a good citizen and clean up after ourselves. This also re-enables the
441 // idle-shutdown behavior.
442 StackSamplingProfiler::TestPeer::Reset();
443 }
444
445 protected:
module_cache()446 ModuleCache* module_cache() { return &module_cache_; }
447
448 private:
449 ModuleCache module_cache_;
450 base::test::TaskEnvironment task_environment_;
451 };
452
453 } // namespace
454
455 // Checks that the basic expected information is present in sampled frames.
456 //
457 // macOS ASAN is not yet supported - crbug.com/718628.
458 //
459 // TODO(crbug.com/40702833): Enable this test again for Android with
460 // ASAN. This is now disabled because the android-asan bot fails.
461 //
462 // If we're running the ChromeOS unit tests on Linux, this test will never pass
463 // because Ubuntu's libc isn't compiled with frame pointers. Skip if not a real
464 // ChromeOS device.
465 #if (defined(ADDRESS_SANITIZER) && BUILDFLAG(IS_APPLE)) || \
466 (defined(ADDRESS_SANITIZER) && BUILDFLAG(IS_ANDROID)) || \
467 (BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_DEVICE))
468 #define MAYBE_Basic DISABLED_Basic
469 #else
470 #define MAYBE_Basic Basic
471 #endif
PROFILER_TEST_F(StackSamplingProfilerTest,MAYBE_Basic)472 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_Basic) {
473 UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
474 const std::vector<Frame>& sample = SampleScenario(&scenario, module_cache());
475
476 // Check that all the modules are valid.
477 for (const auto& frame : sample)
478 EXPECT_NE(nullptr, frame.module);
479
480 // The stack should contain a full unwind.
481 ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
482 scenario.GetSetupFunctionAddressRange(),
483 scenario.GetOuterFunctionAddressRange()});
484 }
485
486 // A simple unwinder that always generates one frame then aborts the stack walk.
487 class TestAuxUnwinder : public Unwinder {
488 public:
TestAuxUnwinder(const Frame & frame_to_report,base::RepeatingClosure add_initial_modules_callback)489 TestAuxUnwinder(const Frame& frame_to_report,
490 base::RepeatingClosure add_initial_modules_callback)
491 : frame_to_report_(frame_to_report),
492 add_initial_modules_callback_(std::move(add_initial_modules_callback)) {
493 }
494
495 TestAuxUnwinder(const TestAuxUnwinder&) = delete;
496 TestAuxUnwinder& operator=(const TestAuxUnwinder&) = delete;
497
InitializeModules()498 void InitializeModules() override {
499 if (add_initial_modules_callback_)
500 add_initial_modules_callback_.Run();
501 }
CanUnwindFrom(const Frame & current_frame) const502 bool CanUnwindFrom(const Frame& current_frame) const override { return true; }
503
TryUnwind(UnwinderStateCapture * capture_state,RegisterContext * thread_context,uintptr_t stack_top,std::vector<Frame> * stack)504 UnwindResult TryUnwind(UnwinderStateCapture* capture_state,
505 RegisterContext* thread_context,
506 uintptr_t stack_top,
507 std::vector<Frame>* stack) override {
508 stack->push_back(frame_to_report_);
509 return UnwindResult::kAborted;
510 }
511
512 private:
513 const Frame frame_to_report_;
514 base::RepeatingClosure add_initial_modules_callback_;
515 };
516
517 // Checks that the profiler handles stacks containing dynamically-allocated
518 // stack memory.
519 // macOS ASAN is not yet supported - crbug.com/718628.
520 // Android is not supported since Chrome unwind tables don't support dynamic
521 // frames.
522 // If we're running the ChromeOS unit tests on Linux, this test will never pass
523 // because Ubuntu's libc isn't compiled with frame pointers. Skip if not a real
524 // ChromeOS device.
525 #if (defined(ADDRESS_SANITIZER) && BUILDFLAG(IS_APPLE)) || \
526 BUILDFLAG(IS_ANDROID) || \
527 (BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_DEVICE))
528 #define MAYBE_Alloca DISABLED_Alloca
529 #else
530 #define MAYBE_Alloca Alloca
531 #endif
PROFILER_TEST_F(StackSamplingProfilerTest,MAYBE_Alloca)532 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_Alloca) {
533 UnwindScenario scenario(BindRepeating(&CallWithAlloca));
534 const std::vector<Frame>& sample = SampleScenario(&scenario, module_cache());
535
536 // The stack should contain a full unwind.
537 ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
538 scenario.GetSetupFunctionAddressRange(),
539 scenario.GetOuterFunctionAddressRange()});
540 }
541
542 // Checks that a stack that runs through another library produces a stack with
543 // the expected functions.
544 // macOS ASAN is not yet supported - crbug.com/718628.
545 // iOS chrome doesn't support loading native libraries.
546 // Android is not supported when EXCLUDE_UNWIND_TABLES |other_library| doesn't
547 // have unwind tables.
548 // TODO(crbug.com/40702833): Enable this test again for Android with
549 // ASAN. This is now disabled because the android-asan bot fails.
550 // If we're running the ChromeOS unit tests on Linux, this test will never pass
551 // because Ubuntu's libc isn't compiled with frame pointers. Skip if not a real
552 // ChromeOS device.
553 #if (defined(ADDRESS_SANITIZER) && BUILDFLAG(IS_APPLE)) || \
554 BUILDFLAG(IS_IOS) || \
555 (BUILDFLAG(IS_ANDROID) && BUILDFLAG(EXCLUDE_UNWIND_TABLES)) || \
556 (BUILDFLAG(IS_ANDROID) && defined(ADDRESS_SANITIZER)) || \
557 (BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_DEVICE))
558 #define MAYBE_OtherLibrary DISABLED_OtherLibrary
559 #else
560 #define MAYBE_OtherLibrary OtherLibrary
561 #endif
PROFILER_TEST_F(StackSamplingProfilerTest,MAYBE_OtherLibrary)562 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_OtherLibrary) {
563 ScopedNativeLibrary other_library(LoadOtherLibrary());
564 UnwindScenario scenario(
565 BindRepeating(&CallThroughOtherLibrary, Unretained(other_library.get())));
566 const std::vector<Frame>& sample = SampleScenario(&scenario, module_cache());
567
568 // The stack should contain a full unwind.
569 ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
570 scenario.GetSetupFunctionAddressRange(),
571 scenario.GetOuterFunctionAddressRange()});
572 }
573
574 // Checks that a stack that runs through a library that is unloading produces a
575 // stack, and doesn't crash.
576 // Unloading is synchronous on the Mac, so this test is inapplicable.
577 // Android is not supported when EXCLUDE_UNWIND_TABLES |other_library| doesn't
578 // have unwind tables.
579 // TODO(crbug.com/40702833): Enable this test again for Android with
580 // ASAN. This is now disabled because the android-asan bot fails.
581 // If we're running the ChromeOS unit tests on Linux, this test will never pass
582 // because Ubuntu's libc isn't compiled with frame pointers. Skip if not a real
583 // ChromeOS device.
584 #if BUILDFLAG(IS_APPLE) || \
585 (BUILDFLAG(IS_ANDROID) && BUILDFLAG(EXCLUDE_UNWIND_TABLES)) || \
586 (BUILDFLAG(IS_ANDROID) && defined(ADDRESS_SANITIZER)) || \
587 (BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_DEVICE))
588 #define MAYBE_UnloadingLibrary DISABLED_UnloadingLibrary
589 #else
590 #define MAYBE_UnloadingLibrary UnloadingLibrary
591 #endif
PROFILER_TEST_F(StackSamplingProfilerTest,MAYBE_UnloadingLibrary)592 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadingLibrary) {
593 TestLibraryUnload(false, module_cache());
594 }
595
596 // Checks that a stack that runs through a library that has been unloaded
597 // produces a stack, and doesn't crash.
598 // macOS ASAN is not yet supported - crbug.com/718628.
599 // Android is not supported since modules are found before unwinding.
600 // If we're running the ChromeOS unit tests on Linux, this test will never pass
601 // because Ubuntu's libc isn't compiled with frame pointers. Skip if not a real
602 // ChromeOS device.
603 #if (defined(ADDRESS_SANITIZER) && BUILDFLAG(IS_APPLE)) || \
604 BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS) || \
605 (BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_DEVICE))
606 #define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary
607 #else
608 #define MAYBE_UnloadedLibrary UnloadedLibrary
609 #endif
PROFILER_TEST_F(StackSamplingProfilerTest,MAYBE_UnloadedLibrary)610 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadedLibrary) {
611 TestLibraryUnload(true, module_cache());
612 }
613
614 // Checks that a profiler can stop/destruct without ever having started.
PROFILER_TEST_F(StackSamplingProfilerTest,StopWithoutStarting)615 PROFILER_TEST_F(StackSamplingProfilerTest, StopWithoutStarting) {
616 WithTargetThread(BindLambdaForTesting(
617 [this](SamplingProfilerThreadToken target_thread_token) {
618 SamplingParams params;
619 params.sampling_interval = Milliseconds(0);
620 params.samples_per_profile = 1;
621
622 Profile profile;
623 WaitableEvent sampling_completed(
624 WaitableEvent::ResetPolicy::MANUAL,
625 WaitableEvent::InitialState::NOT_SIGNALED);
626
627 StackSamplingProfiler profiler(
628 target_thread_token, params,
629 std::make_unique<TestProfileBuilder>(
630 module_cache(),
631 BindLambdaForTesting(
632 [&profile, &sampling_completed](Profile result_profile) {
633 profile = std::move(result_profile);
634 sampling_completed.Signal();
635 })),
636 CreateCoreUnwindersFactoryForTesting(module_cache()));
637
638 profiler.Stop(); // Constructed but never started.
639 EXPECT_FALSE(sampling_completed.IsSignaled());
640 }));
641 }
642
643 // Checks that its okay to stop a profiler before it finishes even when the
644 // sampling thread continues to run.
PROFILER_TEST_F(StackSamplingProfilerTest,StopSafely)645 PROFILER_TEST_F(StackSamplingProfilerTest, StopSafely) {
646 // Test delegate that counts samples.
647 class SampleRecordedCounter : public StackSamplerTestDelegate {
648 public:
649 SampleRecordedCounter() = default;
650
651 void OnPreStackWalk() override {
652 AutoLock lock(lock_);
653 ++count_;
654 }
655
656 size_t Get() {
657 AutoLock lock(lock_);
658 return count_;
659 }
660
661 private:
662 Lock lock_;
663 size_t count_ = 0;
664 };
665
666 WithTargetThread(
667 BindLambdaForTesting([](SamplingProfilerThreadToken target_thread_token) {
668 SamplingParams params[2];
669
670 // Providing an initial delay makes it more likely that both will be
671 // scheduled before either starts to run. Once started, samples will
672 // run ordered by their scheduled, interleaved times regardless of
673 // whatever interval the thread wakes up.
674 params[0].initial_delay = Milliseconds(10);
675 params[0].sampling_interval = Milliseconds(1);
676 params[0].samples_per_profile = 100000;
677
678 params[1].initial_delay = Milliseconds(10);
679 params[1].sampling_interval = Milliseconds(1);
680 params[1].samples_per_profile = 100000;
681
682 SampleRecordedCounter samples_recorded[std::size(params)];
683 ModuleCache module_cache1, module_cache2;
684 TestProfilerInfo profiler_info0(target_thread_token, params[0],
685 &module_cache1, &samples_recorded[0]);
686 TestProfilerInfo profiler_info1(target_thread_token, params[1],
687 &module_cache2, &samples_recorded[1]);
688
689 profiler_info0.profiler.Start();
690 profiler_info1.profiler.Start();
691
692 // Wait for both to start accumulating samples. Using a WaitableEvent is
693 // possible but gets complicated later on because there's no way of
694 // knowing if 0 or 1 additional sample will be taken after Stop() and
695 // thus no way of knowing how many Wait() calls to make on it.
696 while (samples_recorded[0].Get() == 0 || samples_recorded[1].Get() == 0)
697 PlatformThread::Sleep(Milliseconds(1));
698
699 // Ensure that the first sampler can be safely stopped while the second
700 // continues to run. The stopped first profiler will still have a
701 // RecordSampleTask pending that will do nothing when executed because
702 // the collection will have been removed by Stop().
703 profiler_info0.profiler.Stop();
704 profiler_info0.completed.Wait();
705 size_t count0 = samples_recorded[0].Get();
706 size_t count1 = samples_recorded[1].Get();
707
708 // Waiting for the second sampler to collect a couple samples ensures
709 // that the pending RecordSampleTask for the first has executed because
710 // tasks are always ordered by their next scheduled time.
711 while (samples_recorded[1].Get() < count1 + 2)
712 PlatformThread::Sleep(Milliseconds(1));
713
714 // Ensure that the first profiler didn't do anything since it was
715 // stopped.
716 EXPECT_EQ(count0, samples_recorded[0].Get());
717 }));
718 }
719
720 // Checks that no sample are captured if the profiling is stopped during the
721 // initial delay.
PROFILER_TEST_F(StackSamplingProfilerTest,StopDuringInitialDelay)722 PROFILER_TEST_F(StackSamplingProfilerTest, StopDuringInitialDelay) {
723 SamplingParams params;
724 params.initial_delay = Seconds(60);
725
726 std::vector<std::vector<Frame>> samples =
727 CaptureSamples(params, Milliseconds(0), module_cache());
728
729 EXPECT_TRUE(samples.empty());
730 }
731
732 // Checks that tasks can be stopped before completion and incomplete samples are
733 // captured.
PROFILER_TEST_F(StackSamplingProfilerTest,StopDuringInterSampleInterval)734 PROFILER_TEST_F(StackSamplingProfilerTest, StopDuringInterSampleInterval) {
735 // Test delegate that counts samples.
736 class SampleRecordedEvent : public StackSamplerTestDelegate {
737 public:
738 SampleRecordedEvent()
739 : sample_recorded_(WaitableEvent::ResetPolicy::MANUAL,
740 WaitableEvent::InitialState::NOT_SIGNALED) {}
741
742 void OnPreStackWalk() override { sample_recorded_.Signal(); }
743
744 void WaitForSample() { sample_recorded_.Wait(); }
745
746 private:
747 WaitableEvent sample_recorded_;
748 };
749
750 WithTargetThread(BindLambdaForTesting(
751 [this](SamplingProfilerThreadToken target_thread_token) {
752 SamplingParams params;
753
754 params.sampling_interval = AVeryLongTimeDelta();
755 params.samples_per_profile = 2;
756
757 SampleRecordedEvent samples_recorded;
758 TestProfilerInfo profiler_info(target_thread_token, params,
759 module_cache(), &samples_recorded);
760
761 profiler_info.profiler.Start();
762
763 // Wait for profiler to start accumulating samples.
764 samples_recorded.WaitForSample();
765
766 // Ensure that it can stop safely.
767 profiler_info.profiler.Stop();
768 profiler_info.completed.Wait();
769
770 EXPECT_EQ(1u, profiler_info.profile.samples.size());
771 }));
772 }
773
PROFILER_TEST_F(StackSamplingProfilerTest,GetNextSampleTime_NormalExecution)774 PROFILER_TEST_F(StackSamplingProfilerTest, GetNextSampleTime_NormalExecution) {
775 const auto& GetNextSampleTime =
776 StackSamplingProfiler::TestPeer::GetNextSampleTime;
777
778 const TimeTicks scheduled_current_sample_time = TimeTicks::UnixEpoch();
779 const TimeDelta sampling_interval = Milliseconds(10);
780
781 // When executing the sample at exactly the scheduled time the next sample
782 // should be one interval later.
783 EXPECT_EQ(scheduled_current_sample_time + sampling_interval,
784 GetNextSampleTime(scheduled_current_sample_time, sampling_interval,
785 scheduled_current_sample_time));
786
787 // When executing the sample less than half an interval after the scheduled
788 // time the next sample also should be one interval later.
789 EXPECT_EQ(scheduled_current_sample_time + sampling_interval,
790 GetNextSampleTime(
791 scheduled_current_sample_time, sampling_interval,
792 scheduled_current_sample_time + 0.4 * sampling_interval));
793
794 // When executing the sample less than half an interval before the scheduled
795 // time the next sample also should be one interval later. This is not
796 // expected to occur in practice since delayed tasks never run early.
797 EXPECT_EQ(scheduled_current_sample_time + sampling_interval,
798 GetNextSampleTime(
799 scheduled_current_sample_time, sampling_interval,
800 scheduled_current_sample_time - 0.4 * sampling_interval));
801 }
802
PROFILER_TEST_F(StackSamplingProfilerTest,GetNextSampleTime_DelayedExecution)803 PROFILER_TEST_F(StackSamplingProfilerTest, GetNextSampleTime_DelayedExecution) {
804 const auto& GetNextSampleTime =
805 StackSamplingProfiler::TestPeer::GetNextSampleTime;
806
807 const TimeTicks scheduled_current_sample_time = TimeTicks::UnixEpoch();
808 const TimeDelta sampling_interval = Milliseconds(10);
809
810 // When executing the sample between 0.5 and 1.5 intervals after the scheduled
811 // time the next sample should be two intervals later.
812 EXPECT_EQ(scheduled_current_sample_time + 2 * sampling_interval,
813 GetNextSampleTime(
814 scheduled_current_sample_time, sampling_interval,
815 scheduled_current_sample_time + 0.6 * sampling_interval));
816 EXPECT_EQ(scheduled_current_sample_time + 2 * sampling_interval,
817 GetNextSampleTime(
818 scheduled_current_sample_time, sampling_interval,
819 scheduled_current_sample_time + 1.0 * sampling_interval));
820 EXPECT_EQ(scheduled_current_sample_time + 2 * sampling_interval,
821 GetNextSampleTime(
822 scheduled_current_sample_time, sampling_interval,
823 scheduled_current_sample_time + 1.4 * sampling_interval));
824
825 // Similarly when executing the sample between 9.5 and 10.5 intervals after
826 // the scheduled time the next sample should be 11 intervals later.
827 EXPECT_EQ(scheduled_current_sample_time + 11 * sampling_interval,
828 GetNextSampleTime(
829 scheduled_current_sample_time, sampling_interval,
830 scheduled_current_sample_time + 9.6 * sampling_interval));
831 EXPECT_EQ(scheduled_current_sample_time + 11 * sampling_interval,
832 GetNextSampleTime(
833 scheduled_current_sample_time, sampling_interval,
834 scheduled_current_sample_time + 10.0 * sampling_interval));
835 EXPECT_EQ(scheduled_current_sample_time + 11 * sampling_interval,
836 GetNextSampleTime(
837 scheduled_current_sample_time, sampling_interval,
838 scheduled_current_sample_time + 10.4 * sampling_interval));
839 }
840
841 // Checks that we can destroy the profiler while profiling.
PROFILER_TEST_F(StackSamplingProfilerTest,DestroyProfilerWhileProfiling)842 PROFILER_TEST_F(StackSamplingProfilerTest, DestroyProfilerWhileProfiling) {
843 SamplingParams params;
844 params.sampling_interval = Milliseconds(10);
845
846 Profile profile;
847 WithTargetThread(BindLambdaForTesting([&, this](SamplingProfilerThreadToken
848 target_thread_token) {
849 std::unique_ptr<StackSamplingProfiler> profiler;
850 auto profile_builder = std::make_unique<TestProfileBuilder>(
851 module_cache(),
852 BindLambdaForTesting([&profile](Profile result_profile) {
853 profile = std::move(result_profile);
854 }));
855 profiler = std::make_unique<StackSamplingProfiler>(
856 target_thread_token, params, std::move(profile_builder),
857 CreateCoreUnwindersFactoryForTesting(module_cache()));
858 profiler->Start();
859 profiler.reset();
860
861 // Wait longer than a sample interval to catch any use-after-free actions by
862 // the profiler thread.
863 PlatformThread::Sleep(Milliseconds(50));
864 }));
865 }
866
867 // Checks that the different profilers may be run.
PROFILER_TEST_F(StackSamplingProfilerTest,CanRunMultipleProfilers)868 PROFILER_TEST_F(StackSamplingProfilerTest, CanRunMultipleProfilers) {
869 SamplingParams params;
870 params.sampling_interval = Milliseconds(0);
871 params.samples_per_profile = 1;
872
873 std::vector<std::vector<Frame>> samples =
874 CaptureSamples(params, AVeryLongTimeDelta(), module_cache());
875 ASSERT_EQ(1u, samples.size());
876
877 samples = CaptureSamples(params, AVeryLongTimeDelta(), module_cache());
878 ASSERT_EQ(1u, samples.size());
879 }
880
881 // Checks that a sampler can be started while another is running.
PROFILER_TEST_F(StackSamplingProfilerTest,MultipleStart)882 PROFILER_TEST_F(StackSamplingProfilerTest, MultipleStart) {
883 WithTargetThread(
884 BindLambdaForTesting([](SamplingProfilerThreadToken target_thread_token) {
885 SamplingParams params1;
886 params1.initial_delay = AVeryLongTimeDelta();
887 params1.samples_per_profile = 1;
888 ModuleCache module_cache1;
889 TestProfilerInfo profiler_info1(target_thread_token, params1,
890 &module_cache1);
891
892 SamplingParams params2;
893 params2.sampling_interval = Milliseconds(1);
894 params2.samples_per_profile = 1;
895 ModuleCache module_cache2;
896 TestProfilerInfo profiler_info2(target_thread_token, params2,
897 &module_cache2);
898
899 profiler_info1.profiler.Start();
900 profiler_info2.profiler.Start();
901 profiler_info2.completed.Wait();
902 EXPECT_EQ(1u, profiler_info2.profile.samples.size());
903 }));
904 }
905
906 // Checks that the profile duration and the sampling interval are calculated
907 // correctly. Also checks that RecordMetadata() is invoked each time a sample
908 // is recorded.
PROFILER_TEST_F(StackSamplingProfilerTest,ProfileGeneralInfo)909 PROFILER_TEST_F(StackSamplingProfilerTest, ProfileGeneralInfo) {
910 WithTargetThread(BindLambdaForTesting(
911 [this](SamplingProfilerThreadToken target_thread_token) {
912 SamplingParams params;
913 params.sampling_interval = Milliseconds(1);
914 params.samples_per_profile = 3;
915
916 TestProfilerInfo profiler_info(target_thread_token, params,
917 module_cache());
918
919 profiler_info.profiler.Start();
920 profiler_info.completed.Wait();
921 EXPECT_EQ(3u, profiler_info.profile.samples.size());
922
923 // The profile duration should be greater than the total sampling
924 // intervals.
925 EXPECT_GT(profiler_info.profile.profile_duration,
926 profiler_info.profile.sampling_period * 3);
927
928 EXPECT_EQ(Milliseconds(1), profiler_info.profile.sampling_period);
929
930 // The number of invocations of RecordMetadata() should be equal to the
931 // number of samples recorded.
932 EXPECT_EQ(3, profiler_info.profile.record_metadata_count);
933 }));
934 }
935
936 // Checks that the sampling thread can shut down.
PROFILER_TEST_F(StackSamplingProfilerTest,SamplerIdleShutdown)937 PROFILER_TEST_F(StackSamplingProfilerTest, SamplerIdleShutdown) {
938 SamplingParams params;
939 params.sampling_interval = Milliseconds(0);
940 params.samples_per_profile = 1;
941
942 std::vector<std::vector<Frame>> samples =
943 CaptureSamples(params, AVeryLongTimeDelta(), module_cache());
944 ASSERT_EQ(1u, samples.size());
945
946 // Capture thread should still be running at this point.
947 ASSERT_TRUE(StackSamplingProfiler::TestPeer::IsSamplingThreadRunning());
948
949 // Initiate an "idle" shutdown and ensure it happens. Idle-shutdown was
950 // disabled by the test fixture so the test will fail due to a timeout if
951 // it does not exit.
952 StackSamplingProfiler::TestPeer::PerformSamplingThreadIdleShutdown(false);
953
954 // While the shutdown has been initiated, the actual exit of the thread still
955 // happens asynchronously. Watch until the thread actually exits. This test
956 // will time-out in the case of failure.
957 while (StackSamplingProfiler::TestPeer::IsSamplingThreadRunning())
958 PlatformThread::Sleep(Milliseconds(1));
959 }
960
961 // Checks that additional requests will restart a stopped profiler.
PROFILER_TEST_F(StackSamplingProfilerTest,WillRestartSamplerAfterIdleShutdown)962 PROFILER_TEST_F(StackSamplingProfilerTest,
963 WillRestartSamplerAfterIdleShutdown) {
964 SamplingParams params;
965 params.sampling_interval = Milliseconds(0);
966 params.samples_per_profile = 1;
967
968 std::vector<std::vector<Frame>> samples =
969 CaptureSamples(params, AVeryLongTimeDelta(), module_cache());
970 ASSERT_EQ(1u, samples.size());
971
972 // Capture thread should still be running at this point.
973 ASSERT_TRUE(StackSamplingProfiler::TestPeer::IsSamplingThreadRunning());
974
975 // Post a ShutdownTask on the sampling thread which, when executed, will
976 // mark the thread as EXITING and begin shut down of the thread.
977 StackSamplingProfiler::TestPeer::PerformSamplingThreadIdleShutdown(false);
978
979 // Ensure another capture will start the sampling thread and run.
980 samples = CaptureSamples(params, AVeryLongTimeDelta(), module_cache());
981 ASSERT_EQ(1u, samples.size());
982 EXPECT_TRUE(StackSamplingProfiler::TestPeer::IsSamplingThreadRunning());
983 }
984
985 // Checks that it's safe to stop a task after it's completed and the sampling
986 // thread has shut-down for being idle.
PROFILER_TEST_F(StackSamplingProfilerTest,StopAfterIdleShutdown)987 PROFILER_TEST_F(StackSamplingProfilerTest, StopAfterIdleShutdown) {
988 WithTargetThread(BindLambdaForTesting(
989 [this](SamplingProfilerThreadToken target_thread_token) {
990 SamplingParams params;
991
992 params.sampling_interval = Milliseconds(1);
993 params.samples_per_profile = 1;
994
995 TestProfilerInfo profiler_info(target_thread_token, params,
996 module_cache());
997
998 profiler_info.profiler.Start();
999 profiler_info.completed.Wait();
1000
1001 // Capture thread should still be running at this point.
1002 ASSERT_TRUE(StackSamplingProfiler::TestPeer::IsSamplingThreadRunning());
1003
1004 // Perform an idle shutdown.
1005 StackSamplingProfiler::TestPeer::PerformSamplingThreadIdleShutdown(
1006 false);
1007
1008 // Stop should be safe though its impossible to know at this moment if
1009 // the sampling thread has completely exited or will just "stop soon".
1010 profiler_info.profiler.Stop();
1011 }));
1012 }
1013
1014 // Checks that profilers can run both before and after the sampling thread has
1015 // started.
PROFILER_TEST_F(StackSamplingProfilerTest,ProfileBeforeAndAfterSamplingThreadRunning)1016 PROFILER_TEST_F(StackSamplingProfilerTest,
1017 ProfileBeforeAndAfterSamplingThreadRunning) {
1018 WithTargetThread(
1019 BindLambdaForTesting([](SamplingProfilerThreadToken target_thread_token) {
1020 ModuleCache module_cache1;
1021 ModuleCache module_cache2;
1022
1023 std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos;
1024 profiler_infos.push_back(std::make_unique<TestProfilerInfo>(
1025 target_thread_token,
1026 SamplingParams{/*initial_delay=*/AVeryLongTimeDelta(),
1027 /*samples_per_profile=*/1,
1028 /*sampling_interval=*/Milliseconds(1)},
1029 &module_cache1));
1030 profiler_infos.push_back(std::make_unique<TestProfilerInfo>(
1031 target_thread_token,
1032 SamplingParams{/*initial_delay=*/Milliseconds(0),
1033 /*samples_per_profile=*/1,
1034 /*sampling_interval=*/Milliseconds(1)},
1035 &module_cache2));
1036
1037 // First profiler is started when there has never been a sampling
1038 // thread.
1039 EXPECT_FALSE(
1040 StackSamplingProfiler::TestPeer::IsSamplingThreadRunning());
1041 profiler_infos[0]->profiler.Start();
1042 // Second profiler is started when sampling thread is already running.
1043 EXPECT_TRUE(StackSamplingProfiler::TestPeer::IsSamplingThreadRunning());
1044 profiler_infos[1]->profiler.Start();
1045
1046 // Only the second profiler should finish before test times out.
1047 size_t completed_profiler = WaitForSamplingComplete(profiler_infos);
1048 EXPECT_EQ(1U, completed_profiler);
1049 }));
1050 }
1051
1052 // Checks that an idle-shutdown task will abort if a new profiler starts
1053 // between when it was posted and when it runs.
PROFILER_TEST_F(StackSamplingProfilerTest,IdleShutdownAbort)1054 PROFILER_TEST_F(StackSamplingProfilerTest, IdleShutdownAbort) {
1055 WithTargetThread(BindLambdaForTesting(
1056 [this](SamplingProfilerThreadToken target_thread_token) {
1057 SamplingParams params;
1058
1059 params.sampling_interval = Milliseconds(1);
1060 params.samples_per_profile = 1;
1061
1062 TestProfilerInfo profiler_info(target_thread_token, params,
1063 module_cache());
1064
1065 profiler_info.profiler.Start();
1066 profiler_info.completed.Wait();
1067 EXPECT_EQ(1u, profiler_info.profile.samples.size());
1068
1069 // Perform an idle shutdown but simulate that a new capture is started
1070 // before it can actually run.
1071 StackSamplingProfiler::TestPeer::PerformSamplingThreadIdleShutdown(
1072 true);
1073
1074 // Though the shutdown-task has been executed, any actual exit of the
1075 // thread is asynchronous so there is no way to detect that *didn't*
1076 // exit except to wait a reasonable amount of time and then check. Since
1077 // the thread was just running ("perform" blocked until it was), it
1078 // should finish almost immediately and without any waiting for tasks or
1079 // events.
1080 PlatformThread::Sleep(Milliseconds(200));
1081 EXPECT_TRUE(StackSamplingProfiler::TestPeer::IsSamplingThreadRunning());
1082
1083 // Ensure that it's still possible to run another sampler.
1084 TestProfilerInfo another_info(target_thread_token, params,
1085 module_cache());
1086 another_info.profiler.Start();
1087 another_info.completed.Wait();
1088 EXPECT_EQ(1u, another_info.profile.samples.size());
1089 }));
1090 }
1091
1092 // Checks that synchronized multiple sampling requests execute in parallel.
PROFILER_TEST_F(StackSamplingProfilerTest,ConcurrentProfiling_InSync)1093 PROFILER_TEST_F(StackSamplingProfilerTest, ConcurrentProfiling_InSync) {
1094 WithTargetThread(
1095 BindLambdaForTesting([](SamplingProfilerThreadToken target_thread_token) {
1096 ModuleCache module_cache1;
1097 ModuleCache module_cache2;
1098
1099 // Providing an initial delay makes it more likely that both will be
1100 // scheduled before either starts to run. Once started, samples will
1101 // run ordered by their scheduled, interleaved times regardless of
1102 // whatever interval the thread wakes up. Thus, total execution time
1103 // will be 10ms (delay) + 10x1ms (sampling) + 1/2 timer minimum
1104 // interval.
1105 std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos;
1106 profiler_infos.push_back(std::make_unique<TestProfilerInfo>(
1107 target_thread_token,
1108 SamplingParams{/*initial_delay=*/Milliseconds(10),
1109 /*samples_per_profile=*/9,
1110 /*sampling_interval=*/Milliseconds(1)},
1111 &module_cache1));
1112 profiler_infos.push_back(std::make_unique<TestProfilerInfo>(
1113 target_thread_token,
1114 SamplingParams{/*initial_delay=*/Milliseconds(11),
1115 /*samples_per_profile=*/8,
1116 /*sampling_interval=*/Milliseconds(1)},
1117 &module_cache2));
1118
1119 profiler_infos[0]->profiler.Start();
1120 profiler_infos[1]->profiler.Start();
1121
1122 // Wait for one profiler to finish.
1123 size_t completed_profiler = WaitForSamplingComplete(profiler_infos);
1124
1125 size_t other_profiler = 1 - completed_profiler;
1126 // Wait for the other profiler to finish.
1127 profiler_infos[other_profiler]->completed.Wait();
1128
1129 // Ensure each got the correct number of samples.
1130 EXPECT_EQ(9u, profiler_infos[0]->profile.samples.size());
1131 EXPECT_EQ(8u, profiler_infos[1]->profile.samples.size());
1132 }));
1133 }
1134
1135 // Checks that several mixed sampling requests execute in parallel.
PROFILER_TEST_F(StackSamplingProfilerTest,ConcurrentProfiling_Mixed)1136 PROFILER_TEST_F(StackSamplingProfilerTest, ConcurrentProfiling_Mixed) {
1137 WithTargetThread(
1138 BindLambdaForTesting([](SamplingProfilerThreadToken target_thread_token) {
1139 std::vector<ModuleCache> module_caches(3);
1140
1141 std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos;
1142 profiler_infos.push_back(std::make_unique<TestProfilerInfo>(
1143 target_thread_token,
1144 SamplingParams{/*initial_delay=*/Milliseconds(8),
1145 /*samples_per_profile=*/10,
1146 /*sampling_interval=*/Milliseconds(4)},
1147 &module_caches[0]));
1148 profiler_infos.push_back(std::make_unique<TestProfilerInfo>(
1149 target_thread_token,
1150 SamplingParams{/*initial_delay=*/Milliseconds(9),
1151 /*samples_per_profile=*/10,
1152 /*sampling_interval=*/Milliseconds(3)},
1153 &module_caches[1]));
1154 profiler_infos.push_back(std::make_unique<TestProfilerInfo>(
1155 target_thread_token,
1156 SamplingParams{/*initial_delay=*/Milliseconds(10),
1157 /*samples_per_profile=*/10,
1158 /*sampling_interval=*/Milliseconds(2)},
1159 &module_caches[2]));
1160
1161 for (auto& i : profiler_infos) {
1162 i->profiler.Start();
1163 }
1164
1165 // Wait for one profiler to finish.
1166 size_t completed_profiler = WaitForSamplingComplete(profiler_infos);
1167 EXPECT_EQ(10u,
1168 profiler_infos[completed_profiler]->profile.samples.size());
1169 // Stop and destroy all profilers, always in the same order. Don't
1170 // crash.
1171 for (auto& i : profiler_infos) {
1172 i->profiler.Stop();
1173 }
1174 for (auto& i : profiler_infos) {
1175 i.reset();
1176 }
1177 }));
1178 }
1179
1180 // Checks that different threads can be sampled in parallel.
PROFILER_TEST_F(StackSamplingProfilerTest,MultipleSampledThreads)1181 PROFILER_TEST_F(StackSamplingProfilerTest, MultipleSampledThreads) {
1182 UnwindScenario scenario1(BindRepeating(&CallWithPlainFunction));
1183 UnwindScenario::SampleEvents events1;
1184 TargetThread target_thread1(
1185 BindLambdaForTesting([&] { scenario1.Execute(&events1); }));
1186 target_thread1.Start();
1187 events1.ready_for_sample.Wait();
1188
1189 UnwindScenario scenario2(BindRepeating(&CallWithPlainFunction));
1190 UnwindScenario::SampleEvents events2;
1191 TargetThread target_thread2(
1192 BindLambdaForTesting([&] { scenario2.Execute(&events2); }));
1193 target_thread2.Start();
1194 events2.ready_for_sample.Wait();
1195
1196 // Providing an initial delay makes it more likely that both will be
1197 // scheduled before either starts to run. Once started, samples will
1198 // run ordered by their scheduled, interleaved times regardless of
1199 // whatever interval the thread wakes up.
1200 SamplingParams params1, params2;
1201 params1.initial_delay = Milliseconds(10);
1202 params1.sampling_interval = Milliseconds(1);
1203 params1.samples_per_profile = 9;
1204 params2.initial_delay = Milliseconds(10);
1205 params2.sampling_interval = Milliseconds(1);
1206 params2.samples_per_profile = 8;
1207
1208 Profile profile1, profile2;
1209 ModuleCache module_cache1, module_cache2;
1210
1211 WaitableEvent sampling_thread_completed1(
1212 WaitableEvent::ResetPolicy::MANUAL,
1213 WaitableEvent::InitialState::NOT_SIGNALED);
1214 StackSamplingProfiler profiler1(
1215 target_thread1.thread_token(), params1,
1216 std::make_unique<TestProfileBuilder>(
1217 &module_cache1,
1218 BindLambdaForTesting(
1219 [&profile1, &sampling_thread_completed1](Profile result_profile) {
1220 profile1 = std::move(result_profile);
1221 sampling_thread_completed1.Signal();
1222 })),
1223 CreateCoreUnwindersFactoryForTesting(&module_cache1));
1224
1225 WaitableEvent sampling_thread_completed2(
1226 WaitableEvent::ResetPolicy::MANUAL,
1227 WaitableEvent::InitialState::NOT_SIGNALED);
1228 StackSamplingProfiler profiler2(
1229 target_thread2.thread_token(), params2,
1230 std::make_unique<TestProfileBuilder>(
1231 &module_cache2,
1232 BindLambdaForTesting(
1233 [&profile2, &sampling_thread_completed2](Profile result_profile) {
1234 profile2 = std::move(result_profile);
1235 sampling_thread_completed2.Signal();
1236 })),
1237 CreateCoreUnwindersFactoryForTesting(&module_cache2));
1238
1239 // Finally the real work.
1240 profiler1.Start();
1241 profiler2.Start();
1242 sampling_thread_completed1.Wait();
1243 sampling_thread_completed2.Wait();
1244 EXPECT_EQ(9u, profile1.samples.size());
1245 EXPECT_EQ(8u, profile2.samples.size());
1246
1247 events1.sample_finished.Signal();
1248 events2.sample_finished.Signal();
1249 target_thread1.Join();
1250 target_thread2.Join();
1251 }
1252
1253 // A simple thread that runs a profiler on another thread.
1254 class ProfilerThread : public SimpleThread {
1255 public:
ProfilerThread(const std::string & name,SamplingProfilerThreadToken thread_token,const SamplingParams & params,ModuleCache * module_cache)1256 ProfilerThread(const std::string& name,
1257 SamplingProfilerThreadToken thread_token,
1258 const SamplingParams& params,
1259 ModuleCache* module_cache)
1260 : SimpleThread(name, Options()),
1261 run_(WaitableEvent::ResetPolicy::MANUAL,
1262 WaitableEvent::InitialState::NOT_SIGNALED),
1263 completed_(WaitableEvent::ResetPolicy::MANUAL,
1264 WaitableEvent::InitialState::NOT_SIGNALED),
1265 profiler_(thread_token,
1266 params,
1267 std::make_unique<TestProfileBuilder>(
1268 module_cache,
1269 BindLambdaForTesting([this](Profile result_profile) {
1270 profile_ = std::move(result_profile);
1271 completed_.Signal();
1272 })),
1273 CreateCoreUnwindersFactoryForTesting(module_cache)) {}
Run()1274 void Run() override {
1275 run_.Wait();
1276 profiler_.Start();
1277 }
1278
Go()1279 void Go() { run_.Signal(); }
1280
Wait()1281 void Wait() { completed_.Wait(); }
1282
profile()1283 Profile& profile() { return profile_; }
1284
1285 private:
1286 WaitableEvent run_;
1287
1288 Profile profile_;
1289 WaitableEvent completed_;
1290 StackSamplingProfiler profiler_;
1291 };
1292
1293 // Checks that different threads can run samplers in parallel.
PROFILER_TEST_F(StackSamplingProfilerTest,MultipleProfilerThreads)1294 PROFILER_TEST_F(StackSamplingProfilerTest, MultipleProfilerThreads) {
1295 WithTargetThread(
1296 BindLambdaForTesting([](SamplingProfilerThreadToken target_thread_token) {
1297 // Providing an initial delay makes it more likely that both will be
1298 // scheduled before either starts to run. Once started, samples will
1299 // run ordered by their scheduled, interleaved times regardless of
1300 // whatever interval the thread wakes up.
1301 SamplingParams params1, params2;
1302 params1.initial_delay = Milliseconds(10);
1303 params1.sampling_interval = Milliseconds(1);
1304 params1.samples_per_profile = 9;
1305 params2.initial_delay = Milliseconds(10);
1306 params2.sampling_interval = Milliseconds(1);
1307 params2.samples_per_profile = 8;
1308
1309 // Start the profiler threads and give them a moment to get going.
1310 ModuleCache module_cache1;
1311 ProfilerThread profiler_thread1("profiler1", target_thread_token,
1312 params1, &module_cache1);
1313 ModuleCache module_cache2;
1314 ProfilerThread profiler_thread2("profiler2", target_thread_token,
1315 params2, &module_cache2);
1316 profiler_thread1.Start();
1317 profiler_thread2.Start();
1318 PlatformThread::Sleep(Milliseconds(10));
1319
1320 // This will (approximately) synchronize the two threads.
1321 profiler_thread1.Go();
1322 profiler_thread2.Go();
1323
1324 // Wait for them both to finish and validate collection.
1325 profiler_thread1.Wait();
1326 profiler_thread2.Wait();
1327 EXPECT_EQ(9u, profiler_thread1.profile().samples.size());
1328 EXPECT_EQ(8u, profiler_thread2.profile().samples.size());
1329
1330 profiler_thread1.Join();
1331 profiler_thread2.Join();
1332 }));
1333 }
1334
PROFILER_TEST_F(StackSamplingProfilerTest,AddAuxUnwinder_BeforeStart)1335 PROFILER_TEST_F(StackSamplingProfilerTest, AddAuxUnwinder_BeforeStart) {
1336 SamplingParams params;
1337 params.sampling_interval = Milliseconds(0);
1338 params.samples_per_profile = 1;
1339
1340 UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
1341
1342 int add_initial_modules_invocation_count = 0;
1343 const auto add_initial_modules_callback =
1344 [&add_initial_modules_invocation_count] {
1345 ++add_initial_modules_invocation_count;
1346 };
1347
1348 Profile profile;
1349 WithTargetThread(
1350 &scenario,
1351 BindLambdaForTesting(
1352 [&](SamplingProfilerThreadToken target_thread_token) {
1353 WaitableEvent sampling_thread_completed(
1354 WaitableEvent::ResetPolicy::MANUAL,
1355 WaitableEvent::InitialState::NOT_SIGNALED);
1356 StackSamplingProfiler profiler(
1357 target_thread_token, params,
1358 std::make_unique<TestProfileBuilder>(
1359 module_cache(),
1360 BindLambdaForTesting([&profile, &sampling_thread_completed](
1361 Profile result_profile) {
1362 profile = std::move(result_profile);
1363 sampling_thread_completed.Signal();
1364 })),
1365 CreateCoreUnwindersFactoryForTesting(module_cache()));
1366 profiler.AddAuxUnwinder(std::make_unique<TestAuxUnwinder>(
1367 Frame(23, nullptr),
1368 BindLambdaForTesting(add_initial_modules_callback)));
1369 profiler.Start();
1370 sampling_thread_completed.Wait();
1371 }));
1372
1373 ASSERT_EQ(1, add_initial_modules_invocation_count);
1374
1375 // The sample should have one frame from the context values aFFnd one from the
1376 // TestAuxUnwinder.
1377 ASSERT_EQ(1u, profile.samples.size());
1378 const std::vector<Frame>& frames = profile.samples[0];
1379
1380 ASSERT_EQ(2u, frames.size());
1381 EXPECT_EQ(23u, frames[1].instruction_pointer);
1382 EXPECT_EQ(nullptr, frames[1].module);
1383 }
1384
PROFILER_TEST_F(StackSamplingProfilerTest,AddAuxUnwinder_AfterStart)1385 PROFILER_TEST_F(StackSamplingProfilerTest, AddAuxUnwinder_AfterStart) {
1386 SamplingParams params;
1387 params.sampling_interval = Milliseconds(10);
1388 params.samples_per_profile = 2;
1389
1390 UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
1391
1392 int add_initial_modules_invocation_count = 0;
1393 const auto add_initial_modules_callback =
1394 [&add_initial_modules_invocation_count] {
1395 ++add_initial_modules_invocation_count;
1396 };
1397
1398 Profile profile;
1399 WithTargetThread(
1400 &scenario,
1401 BindLambdaForTesting(
1402 [&](SamplingProfilerThreadToken target_thread_token) {
1403 WaitableEvent sampling_thread_completed(
1404 WaitableEvent::ResetPolicy::MANUAL,
1405 WaitableEvent::InitialState::NOT_SIGNALED);
1406 StackSamplingProfiler profiler(
1407 target_thread_token, params,
1408 std::make_unique<TestProfileBuilder>(
1409 module_cache(),
1410 BindLambdaForTesting([&profile, &sampling_thread_completed](
1411 Profile result_profile) {
1412 profile = std::move(result_profile);
1413 sampling_thread_completed.Signal();
1414 })),
1415 CreateCoreUnwindersFactoryForTesting(module_cache()));
1416 profiler.Start();
1417 profiler.AddAuxUnwinder(std::make_unique<TestAuxUnwinder>(
1418 Frame(23, nullptr),
1419 BindLambdaForTesting(add_initial_modules_callback)));
1420 sampling_thread_completed.Wait();
1421 }));
1422
1423 ASSERT_EQ(1, add_initial_modules_invocation_count);
1424
1425 // The sample should have one frame from the context values and one from the
1426 // TestAuxUnwinder.
1427 ASSERT_EQ(2u, profile.samples.size());
1428
1429 // Whether the aux unwinder is available for the first sample is racy, so rely
1430 // on the second sample.
1431 const std::vector<Frame>& frames = profile.samples[1];
1432 ASSERT_EQ(2u, frames.size());
1433 EXPECT_EQ(23u, frames[1].instruction_pointer);
1434 EXPECT_EQ(nullptr, frames[1].module);
1435 }
1436
PROFILER_TEST_F(StackSamplingProfilerTest,AddAuxUnwinder_AfterStop)1437 PROFILER_TEST_F(StackSamplingProfilerTest, AddAuxUnwinder_AfterStop) {
1438 SamplingParams params;
1439 params.sampling_interval = Milliseconds(0);
1440 params.samples_per_profile = 1;
1441
1442 UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
1443
1444 Profile profile;
1445 WithTargetThread(
1446 &scenario,
1447 BindLambdaForTesting(
1448 [&](SamplingProfilerThreadToken target_thread_token) {
1449 WaitableEvent sampling_thread_completed(
1450 WaitableEvent::ResetPolicy::MANUAL,
1451 WaitableEvent::InitialState::NOT_SIGNALED);
1452 StackSamplingProfiler profiler(
1453 target_thread_token, params,
1454 std::make_unique<TestProfileBuilder>(
1455 module_cache(),
1456 BindLambdaForTesting([&profile, &sampling_thread_completed](
1457 Profile result_profile) {
1458 profile = std::move(result_profile);
1459 sampling_thread_completed.Signal();
1460 })),
1461 CreateCoreUnwindersFactoryForTesting(module_cache()));
1462 profiler.Start();
1463 profiler.Stop();
1464 profiler.AddAuxUnwinder(std::make_unique<TestAuxUnwinder>(
1465 Frame(23, nullptr), base::RepeatingClosure()));
1466 sampling_thread_completed.Wait();
1467 }));
1468
1469 // The AuxUnwinder should be accepted without error. It will have no effect
1470 // since the collection has stopped.
1471 }
1472
1473 // Checks that requests to apply metadata to past samples are passed on to the
1474 // profile builder.
PROFILER_TEST_F(StackSamplingProfilerTest,ApplyMetadataToPastSamples_PassedToProfileBuilder)1475 PROFILER_TEST_F(StackSamplingProfilerTest,
1476 ApplyMetadataToPastSamples_PassedToProfileBuilder) {
1477 // Runs the passed closure on the profiler thread after a sample is taken.
1478 class PostSampleInvoker : public StackSamplerTestDelegate {
1479 public:
1480 explicit PostSampleInvoker(RepeatingClosure post_sample_closure)
1481 : post_sample_closure_(std::move(post_sample_closure)) {}
1482
1483 void OnPreStackWalk() override { post_sample_closure_.Run(); }
1484
1485 private:
1486 RepeatingClosure post_sample_closure_;
1487 };
1488
1489 // Thread-safe representation of the times that samples were taken.
1490 class SynchronizedSampleTimes {
1491 public:
1492 void AddNow() {
1493 AutoLock lock(lock_);
1494 times_.push_back(TimeTicks::Now());
1495 }
1496
1497 std::vector<TimeTicks> GetTimes() {
1498 AutoLock lock(lock_);
1499 return times_;
1500 }
1501
1502 private:
1503 Lock lock_;
1504 std::vector<TimeTicks> times_;
1505 };
1506
1507 SamplingParams params;
1508 params.sampling_interval = Milliseconds(10);
1509 // 10,000 samples ensures the profiler continues running until manually
1510 // stopped, after applying metadata.
1511 params.samples_per_profile = 10000;
1512
1513 UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
1514
1515 std::vector<TimeTicks> sample_times;
1516 Profile profile;
1517 WithTargetThread(
1518 &scenario,
1519 BindLambdaForTesting(
1520 [&](SamplingProfilerThreadToken target_thread_token) {
1521 SynchronizedSampleTimes synchronized_sample_times;
1522 WaitableEvent sample_seen(WaitableEvent::ResetPolicy::AUTOMATIC);
1523 PostSampleInvoker post_sample_invoker(BindLambdaForTesting([&] {
1524 synchronized_sample_times.AddNow();
1525 sample_seen.Signal();
1526 }));
1527
1528 StackSamplingProfiler profiler(
1529 target_thread_token, params,
1530 std::make_unique<TestProfileBuilder>(
1531 module_cache(),
1532 BindLambdaForTesting([&profile](Profile result_profile) {
1533 profile = std::move(result_profile);
1534 })),
1535 CreateCoreUnwindersFactoryForTesting(module_cache()),
1536 RepeatingClosure(), &post_sample_invoker);
1537 profiler.Start();
1538 // Wait for 5 samples to be collected.
1539 for (int i = 0; i < 5; ++i)
1540 sample_seen.Wait();
1541 sample_times = synchronized_sample_times.GetTimes();
1542 // Record metadata on past samples, with and without a key value.
1543 // The range [times[1], times[3]] is guaranteed to include only
1544 // samples 2 and 3, and likewise [times[2], times[4]] is guaranteed
1545 // to include only samples 3 and 4.
1546 ApplyMetadataToPastSamples(sample_times[1], sample_times[3],
1547 "TestMetadata1", 10,
1548 base::SampleMetadataScope::kProcess);
1549 ApplyMetadataToPastSamples(sample_times[2], sample_times[4],
1550 "TestMetadata2", 100, 11,
1551 base::SampleMetadataScope::kProcess);
1552 profiler.Stop();
1553 }));
1554
1555 ASSERT_EQ(2u, profile.retrospective_metadata.size());
1556
1557 const RetrospectiveMetadata& metadata1 = profile.retrospective_metadata[0];
1558 EXPECT_EQ(sample_times[1], metadata1.period_start);
1559 EXPECT_EQ(sample_times[3], metadata1.period_end);
1560 EXPECT_EQ(HashMetricName("TestMetadata1"), metadata1.item.name_hash);
1561 EXPECT_FALSE(metadata1.item.key.has_value());
1562 EXPECT_EQ(10, metadata1.item.value);
1563
1564 const RetrospectiveMetadata& metadata2 = profile.retrospective_metadata[1];
1565 EXPECT_EQ(sample_times[2], metadata2.period_start);
1566 EXPECT_EQ(sample_times[4], metadata2.period_end);
1567 EXPECT_EQ(HashMetricName("TestMetadata2"), metadata2.item.name_hash);
1568 ASSERT_TRUE(metadata2.item.key.has_value());
1569 EXPECT_EQ(100, *metadata2.item.key);
1570 EXPECT_EQ(11, metadata2.item.value);
1571 }
1572
PROFILER_TEST_F(StackSamplingProfilerTest,ApplyMetadataToPastSamples_PassedToProfileBuilder_MultipleCollections)1573 PROFILER_TEST_F(
1574 StackSamplingProfilerTest,
1575 ApplyMetadataToPastSamples_PassedToProfileBuilder_MultipleCollections) {
1576 SamplingParams params;
1577 params.sampling_interval = Milliseconds(10);
1578 // 10,000 samples ensures the profiler continues running until manually
1579 // stopped, after applying metadata.
1580 params.samples_per_profile = 10000;
1581 ModuleCache module_cache1, module_cache2;
1582
1583 WaitableEvent profiler1_started;
1584 WaitableEvent profiler2_started;
1585 WaitableEvent profiler1_metadata_applied;
1586 WaitableEvent profiler2_metadata_applied;
1587
1588 Profile profile1;
1589 WaitableEvent sampling_completed1;
1590 TargetThread target_thread1(BindLambdaForTesting([&] {
1591 StackSamplingProfiler profiler1(
1592 target_thread1.thread_token(), params,
1593 std::make_unique<TestProfileBuilder>(
1594 &module_cache1, BindLambdaForTesting([&](Profile result_profile) {
1595 profile1 = std::move(result_profile);
1596 sampling_completed1.Signal();
1597 })),
1598 CreateCoreUnwindersFactoryForTesting(&module_cache1),
1599 RepeatingClosure());
1600 profiler1.Start();
1601 profiler1_started.Signal();
1602 profiler2_started.Wait();
1603
1604 // Record metadata on past samples only for this thread. The time range
1605 // shouldn't affect the outcome, it should always be passed to the
1606 // ProfileBuilder.
1607 ApplyMetadataToPastSamples(TimeTicks(), TimeTicks::Now(), "TestMetadata1",
1608 10, 10, SampleMetadataScope::kThread);
1609
1610 profiler1_metadata_applied.Signal();
1611 profiler2_metadata_applied.Wait();
1612 profiler1.Stop();
1613 }));
1614 target_thread1.Start();
1615
1616 Profile profile2;
1617 WaitableEvent sampling_completed2;
1618 TargetThread target_thread2(BindLambdaForTesting([&] {
1619 StackSamplingProfiler profiler2(
1620 target_thread2.thread_token(), params,
1621 std::make_unique<TestProfileBuilder>(
1622 &module_cache2, BindLambdaForTesting([&](Profile result_profile) {
1623 profile2 = std::move(result_profile);
1624 sampling_completed2.Signal();
1625 })),
1626 CreateCoreUnwindersFactoryForTesting(&module_cache2),
1627 RepeatingClosure());
1628 profiler2.Start();
1629 profiler2_started.Signal();
1630 profiler1_started.Wait();
1631
1632 // Record metadata on past samples only for this thread.
1633 ApplyMetadataToPastSamples(TimeTicks(), TimeTicks::Now(), "TestMetadata2",
1634 20, 20, SampleMetadataScope::kThread);
1635
1636 profiler2_metadata_applied.Signal();
1637 profiler1_metadata_applied.Wait();
1638 profiler2.Stop();
1639 }));
1640 target_thread2.Start();
1641
1642 target_thread1.Join();
1643 target_thread2.Join();
1644
1645 // Wait for the profile to be captured before checking expectations.
1646 sampling_completed1.Wait();
1647 sampling_completed2.Wait();
1648
1649 ASSERT_EQ(1u, profile1.retrospective_metadata.size());
1650 ASSERT_EQ(1u, profile2.retrospective_metadata.size());
1651
1652 {
1653 const RetrospectiveMetadata& metadata1 = profile1.retrospective_metadata[0];
1654 EXPECT_EQ(HashMetricName("TestMetadata1"), metadata1.item.name_hash);
1655 ASSERT_TRUE(metadata1.item.key.has_value());
1656 EXPECT_EQ(10, *metadata1.item.key);
1657 EXPECT_EQ(10, metadata1.item.value);
1658 }
1659 {
1660 const RetrospectiveMetadata& metadata2 = profile2.retrospective_metadata[0];
1661 EXPECT_EQ(HashMetricName("TestMetadata2"), metadata2.item.name_hash);
1662 ASSERT_TRUE(metadata2.item.key.has_value());
1663 EXPECT_EQ(20, *metadata2.item.key);
1664 EXPECT_EQ(20, metadata2.item.value);
1665 }
1666 }
1667
1668 // Checks that requests to add profile metadata are passed on to the profile
1669 // builder.
PROFILER_TEST_F(StackSamplingProfilerTest,AddProfileMetadata_PassedToProfileBuilder)1670 PROFILER_TEST_F(StackSamplingProfilerTest,
1671 AddProfileMetadata_PassedToProfileBuilder) {
1672 // Runs the passed closure on the profiler thread after a sample is taken.
1673 class PostSampleInvoker : public StackSamplerTestDelegate {
1674 public:
1675 explicit PostSampleInvoker(RepeatingClosure post_sample_closure)
1676 : post_sample_closure_(std::move(post_sample_closure)) {}
1677
1678 void OnPreStackWalk() override { post_sample_closure_.Run(); }
1679
1680 private:
1681 RepeatingClosure post_sample_closure_;
1682 };
1683
1684 SamplingParams params;
1685 params.sampling_interval = Milliseconds(10);
1686 // 10,000 samples ensures the profiler continues running until manually
1687 // stopped.
1688 params.samples_per_profile = 10000;
1689
1690 UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
1691
1692 Profile profile;
1693 WithTargetThread(
1694 &scenario,
1695 BindLambdaForTesting(
1696 [&](SamplingProfilerThreadToken target_thread_token) {
1697 WaitableEvent sample_seen(WaitableEvent::ResetPolicy::AUTOMATIC);
1698 PostSampleInvoker post_sample_invoker(
1699 BindLambdaForTesting([&] { sample_seen.Signal(); }));
1700
1701 StackSamplingProfiler profiler(
1702 target_thread_token, params,
1703 std::make_unique<TestProfileBuilder>(
1704 module_cache(),
1705 BindLambdaForTesting([&profile](Profile result_profile) {
1706 profile = std::move(result_profile);
1707 })),
1708 CreateCoreUnwindersFactoryForTesting(module_cache()),
1709 RepeatingClosure(), &post_sample_invoker);
1710 profiler.Start();
1711 sample_seen.Wait();
1712 AddProfileMetadata("TestMetadata", 1, 2,
1713 SampleMetadataScope::kProcess);
1714 profiler.Stop();
1715 }));
1716
1717 ASSERT_EQ(1u, profile.profile_metadata.size());
1718 const MetadataRecorder::Item& item = profile.profile_metadata[0];
1719 EXPECT_EQ(HashMetricName("TestMetadata"), item.name_hash);
1720 EXPECT_EQ(1, *item.key);
1721 EXPECT_EQ(2, item.value);
1722 }
1723
PROFILER_TEST_F(StackSamplingProfilerTest,AddProfileMetadata_PassedToProfileBuilder_MultipleCollections)1724 PROFILER_TEST_F(StackSamplingProfilerTest,
1725 AddProfileMetadata_PassedToProfileBuilder_MultipleCollections) {
1726 SamplingParams params;
1727 params.sampling_interval = Milliseconds(10);
1728 // 10,000 samples ensures the profiler continues running until manually
1729 // stopped.
1730 params.samples_per_profile = 10000;
1731 ModuleCache module_cache1, module_cache2;
1732
1733 WaitableEvent profiler1_started;
1734 WaitableEvent profiler2_started;
1735 WaitableEvent profiler1_metadata_applied;
1736 WaitableEvent profiler2_metadata_applied;
1737
1738 Profile profile1;
1739 WaitableEvent sampling_completed1;
1740 TargetThread target_thread1(BindLambdaForTesting([&] {
1741 StackSamplingProfiler profiler1(
1742 target_thread1.thread_token(), params,
1743 std::make_unique<TestProfileBuilder>(
1744 &module_cache1, BindLambdaForTesting([&](Profile result_profile) {
1745 profile1 = std::move(result_profile);
1746 sampling_completed1.Signal();
1747 })),
1748 CreateCoreUnwindersFactoryForTesting(&module_cache1),
1749 RepeatingClosure());
1750 profiler1.Start();
1751 profiler1_started.Signal();
1752 profiler2_started.Wait();
1753
1754 AddProfileMetadata("TestMetadata1", 1, 2, SampleMetadataScope::kThread);
1755
1756 profiler1_metadata_applied.Signal();
1757 profiler2_metadata_applied.Wait();
1758 profiler1.Stop();
1759 }));
1760 target_thread1.Start();
1761
1762 Profile profile2;
1763 WaitableEvent sampling_completed2;
1764 TargetThread target_thread2(BindLambdaForTesting([&] {
1765 StackSamplingProfiler profiler2(
1766 target_thread2.thread_token(), params,
1767 std::make_unique<TestProfileBuilder>(
1768 &module_cache2, BindLambdaForTesting([&](Profile result_profile) {
1769 profile2 = std::move(result_profile);
1770 sampling_completed2.Signal();
1771 })),
1772 CreateCoreUnwindersFactoryForTesting(&module_cache2),
1773 RepeatingClosure());
1774 profiler2.Start();
1775 profiler2_started.Signal();
1776 profiler1_started.Wait();
1777
1778 AddProfileMetadata("TestMetadata2", 11, 12, SampleMetadataScope::kThread);
1779
1780 profiler2_metadata_applied.Signal();
1781 profiler1_metadata_applied.Wait();
1782 profiler2.Stop();
1783 }));
1784 target_thread2.Start();
1785
1786 target_thread1.Join();
1787 target_thread2.Join();
1788
1789 // Wait for the profile to be captured before checking expectations.
1790 sampling_completed1.Wait();
1791 sampling_completed2.Wait();
1792
1793 ASSERT_EQ(1u, profile1.profile_metadata.size());
1794 ASSERT_EQ(1u, profile2.profile_metadata.size());
1795
1796 {
1797 const MetadataRecorder::Item& item = profile1.profile_metadata[0];
1798 EXPECT_EQ(HashMetricName("TestMetadata1"), item.name_hash);
1799 ASSERT_TRUE(item.key.has_value());
1800 EXPECT_EQ(1, *item.key);
1801 EXPECT_EQ(2, item.value);
1802 }
1803 {
1804 const MetadataRecorder::Item& item = profile2.profile_metadata[0];
1805 EXPECT_EQ(HashMetricName("TestMetadata2"), item.name_hash);
1806 ASSERT_TRUE(item.key.has_value());
1807 EXPECT_EQ(11, *item.key);
1808 EXPECT_EQ(12, item.value);
1809 }
1810 }
1811
1812 } // namespace base
1813