Chromium Code Reviews| Index: base/profiler/stack_sampling_profiler_unittest.cc |
| diff --git a/base/profiler/stack_sampling_profiler_unittest.cc b/base/profiler/stack_sampling_profiler_unittest.cc |
| index dfccab4e1a893ae7da9c768f0e5c17aef4f9b692..e715bfdf296ebed630678b8439fc033d62e50dac 100644 |
| --- a/base/profiler/stack_sampling_profiler_unittest.cc |
| +++ b/base/profiler/stack_sampling_profiler_unittest.cc |
| @@ -2,12 +2,11 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include <sstream> |
| - |
| #include "base/bind.h" |
| #include "base/compiler_specific.h" |
| #include "base/path_service.h" |
| #include "base/profiler/stack_sampling_profiler.h" |
| +#include "base/strings/stringprintf.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/time/time.h" |
| @@ -21,24 +20,28 @@ using Sample = StackSamplingProfiler::Sample; |
| using Profile = StackSamplingProfiler::Profile; |
| namespace { |
| + |
| // A thread to target for profiling, whose stack is guaranteed to contain |
| // SignalAndWaitUntilSignaled() when coordinated with the main thread. |
| class TargetThread : public PlatformThread::Delegate { |
| public: |
| TargetThread(); |
| - // Implementation of PlatformThread::Delegate: |
| + // PlatformThread::Delegate: |
| void ThreadMain() override; |
| // Wait for the thread to have started and be executing in |
|
Peter Kasting
2015/03/30 23:07:35
Waits
Mike Wittman
2015/03/31 01:06:37
Done.
|
| // SignalAndWaitUntilSignaled(). |
| void WaitForThreadStart(); |
| + |
| // Allow the thread to return from SignalAndWaitUntilSignaled() and finish |
|
Peter Kasting
2015/03/30 23:07:35
Allows
Mike Wittman
2015/03/31 01:06:37
Done.
|
| // execution. |
| void SignalThreadToFinish(); |
| // This function is guaranteed to be executing between calls to |
| - // WaitForThreadStart() and SignalThreadToFinish(). |
| + // WaitForThreadStart() and SignalThreadToFinish(). This function is static so |
| + // that we can get a straightforward address for it, rather than dealing with |
|
Peter Kasting
2015/03/30 23:07:35
Nit: "...address for it in one of the tests below,
Mike Wittman
2015/03/31 01:06:37
Done.
|
| + // the complexity of a member function pointer representation. |
| static void SignalAndWaitUntilSignaled(WaitableEvent* thread_started_event, |
| WaitableEvent* finish_event); |
| @@ -109,7 +112,7 @@ void CaptureProfiles(const StackSamplingProfiler::SamplingParams& params, |
| WaitableEvent sampling_thread_completed(true, false); |
| profiles->clear(); |
| StackSamplingProfiler profiler(target_thread.id(), params); |
| - profiler.SetCustomCompletedCallback( |
| + profiler.set_custom_completed_callback( |
| Bind(&SaveProfilesAndSignalEvent, Unretained(profiles), |
| Unretained(&sampling_thread_completed))); |
| profiler.Start(); |
| @@ -125,8 +128,9 @@ void CaptureProfiles(const StackSamplingProfiler::SamplingParams& params, |
| // If this executable was linked with /INCREMENTAL (the default for non-official |
| // debug and release builds on Windows), function addresses do not correspond to |
| // function code itself, but instead to instructions in the Incremental Link |
| -// Table that jump to the functions. Check for a jump instruction and if present |
| -// do a little decompilation to find the function's actual starting address. |
| +// Table that jump to the functions. Checks for a jump instruction and if |
| +// present does a little decompilation to find the function's actual starting |
| +// address. |
| const void* MaybeFixupFunctionAddressForILT(const void* function_address) { |
| #if defined(_WIN64) |
| const unsigned char* opcode = |
| @@ -134,10 +138,10 @@ const void* MaybeFixupFunctionAddressForILT(const void* function_address) { |
| if (*opcode == 0xe9) { |
| // This is a relative jump instruction. Assume we're in the ILT and compute |
| // the function start address from the instruction offset. |
| - const unsigned char* offset = opcode + 1; |
| - const unsigned char* next_instruction = opcode + 5; |
| - return next_instruction + |
| - static_cast<int64>(*reinterpret_cast<const int32*>(offset)); |
| + const int32* offset = reinterpret_cast<const int32*>(opcode + 1); |
| + const unsigned char* next_instruction = |
| + reinterpret_cast<const unsigned char*>(offset + 1); |
| + return next_instruction + *offset; |
| } |
| #endif |
| return function_address; |
| @@ -153,11 +157,9 @@ Sample::const_iterator FindFirstFrameWithinFunction( |
| int function_size) { |
| function_address = MaybeFixupFunctionAddressForILT(function_address); |
| for (auto it = sample.begin(); it != sample.end(); ++it) { |
| - if ((reinterpret_cast<const unsigned char*>(it->instruction_pointer) >= |
| - reinterpret_cast<const unsigned char*>(function_address)) && |
| - (reinterpret_cast<const unsigned char*>(it->instruction_pointer) < |
| - (reinterpret_cast<const unsigned char*>(function_address) + |
| - function_size))) |
| + if ((it->instruction_pointer >= function_address) && |
| + (it->instruction_pointer < |
| + (static_cast<const unsigned char*>(function_address) + function_size))) |
| return it; |
| } |
| return sample.end(); |
| @@ -167,17 +169,19 @@ Sample::const_iterator FindFirstFrameWithinFunction( |
| std::string FormatSampleForDiagnosticOutput( |
| const Sample& sample, |
| const std::vector<Module>& modules) { |
| - std::ostringstream stream; |
| + std::string output; |
| for (const Frame& frame: sample) { |
| - stream << frame.instruction_pointer << " " |
| - << modules[frame.module_index].filename.value() << std::endl; |
| + output += StringPrintf( |
| + "0x%p %s\n", frame.instruction_pointer, |
| + modules[frame.module_index].filename.AsUTF8Unsafe().c_str()); |
| } |
| - return stream.str(); |
| + return output; |
| } |
| // Returns a duration that is longer than the test timeout. We would use |
| // TimeDelta::Max() but https://crbug.com/465948. |
| TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); } |
| + |
| } // namespace |
| @@ -192,9 +196,7 @@ TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); } |
| #endif |
| TEST(StackSamplingProfilerTest, MAYBE_Basic) { |
| StackSamplingProfiler::SamplingParams params; |
| - params.initial_delay = params.burst_interval = params.sampling_interval = |
| - TimeDelta::FromMilliseconds(0); |
| - params.bursts = 1; |
| + params.sampling_interval = TimeDelta::FromMilliseconds(0); |
| params.samples_per_burst = 1; |
| std::vector<Profile> profiles; |
| @@ -202,21 +204,20 @@ TEST(StackSamplingProfilerTest, MAYBE_Basic) { |
| // Check that the profile and samples sizes are correct, and the module |
| // indices are in range. |
| - |
| ASSERT_EQ(1u, profiles.size()); |
| const Profile& profile = profiles[0]; |
| ASSERT_EQ(1u, profile.samples.size()); |
| EXPECT_EQ(params.sampling_interval, profile.sampling_period); |
| const Sample& sample = profile.samples[0]; |
| for (const auto& frame : sample) { |
| - ASSERT_GE(frame.module_index, 0); |
| - ASSERT_LT(frame.module_index, static_cast<int>(profile.modules.size())); |
| + ASSERT_GE(frame.module_index, 0u); |
| + ASSERT_LT(frame.module_index, profile.modules.size()); |
| } |
| // Check that the stack contains a frame for |
| // TargetThread::SignalAndWaitUntilSignaled() and that the frame has this |
| // executable's module. |
| - |
| + // |
| // Since we don't have a good way to know the function size, use 100 bytes as |
| // a reasonable window to locate the instruction pointer. |
| Sample::const_iterator loc = FindFirstFrameWithinFunction( |
| @@ -228,12 +229,10 @@ TEST(StackSamplingProfilerTest, MAYBE_Basic) { |
| << MaybeFixupFunctionAddressForILT( |
| reinterpret_cast<const void*>( |
| &TargetThread::SignalAndWaitUntilSignaled)) |
| - << " was not found in stack:" << std::endl |
| + << " was not found in stack:\n" |
| << FormatSampleForDiagnosticOutput(sample, profile.modules); |
| - |
| FilePath executable_path; |
| - bool got_executable_path = PathService::Get(FILE_EXE, &executable_path); |
| - EXPECT_TRUE(got_executable_path); |
| + EXPECT_TRUE(PathService::Get(FILE_EXE, &executable_path)); |
| EXPECT_EQ(executable_path, profile.modules[loc->module_index].filename); |
| } |
| @@ -246,7 +245,7 @@ TEST(StackSamplingProfilerTest, MAYBE_Basic) { |
| #endif |
| TEST(StackSamplingProfilerTest, MAYBE_MultipleProfilesAndSamples) { |
| StackSamplingProfiler::SamplingParams params; |
| - params.initial_delay = params.burst_interval = params.sampling_interval = |
| + params.burst_interval = params.sampling_interval = |
| TimeDelta::FromMilliseconds(0); |
| params.bursts = 2; |
| params.samples_per_burst = 3; |
| @@ -268,10 +267,7 @@ TEST(StackSamplingProfilerTest, MAYBE_MultipleProfilesAndSamples) { |
| #endif |
| TEST(StackSamplingProfilerTest, MAYBE_StopDuringInitialDelay) { |
| StackSamplingProfiler::SamplingParams params; |
| - params.burst_interval = params.sampling_interval = |
| - TimeDelta::FromMilliseconds(0); |
| params.initial_delay = TimeDelta::FromSeconds(60); |
| - params.bursts = params.samples_per_burst = 1; |
| std::vector<Profile> profiles; |
| CaptureProfiles(params, &profiles, TimeDelta::FromMilliseconds(0)); |
| @@ -288,8 +284,7 @@ TEST(StackSamplingProfilerTest, MAYBE_StopDuringInitialDelay) { |
| #endif |
| TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterBurstInterval) { |
| StackSamplingProfiler::SamplingParams params; |
| - params.initial_delay = params.sampling_interval = |
| - TimeDelta::FromMilliseconds(0); |
| + params.sampling_interval = TimeDelta::FromMilliseconds(0); |
| params.burst_interval = TimeDelta::FromSeconds(60); |
| params.bursts = 2; |
| params.samples_per_burst = 1; |
| @@ -310,9 +305,7 @@ TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterBurstInterval) { |
| #endif |
| TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterSampleInterval) { |
| StackSamplingProfiler::SamplingParams params; |
| - params.initial_delay = params.burst_interval = TimeDelta::FromMilliseconds(0); |
| params.sampling_interval = TimeDelta::FromSeconds(60); |
| - params.bursts = 1; |
| params.samples_per_burst = 2; |
| std::vector<Profile> profiles; |
| @@ -322,3 +315,4 @@ TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterSampleInterval) { |
| } |
| } // namespace tracked_objects |
| + |