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