diff options
author | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-08 17:09:21 +0000 |
---|---|---|
committer | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-08 17:09:21 +0000 |
commit | dbe5d207423cafcd99684cef2f119a7e197798d3 (patch) | |
tree | 2e19e0b01436955084b24f5ad701d3bf6abda538 /base/profiler | |
parent | 1fd253983318446dcaebb317d7767ba0c403bd58 (diff) | |
download | chromium_src-dbe5d207423cafcd99684cef2f119a7e197798d3.zip chromium_src-dbe5d207423cafcd99684cef2f119a7e197798d3.tar.gz chromium_src-dbe5d207423cafcd99684cef2f119a7e197798d3.tar.bz2 |
Revert of Revert 108752 - Support tracking of IPC messages as tasks in profiler
This is a relanding of all the cleanup found in the
original CL, without the hooks to actually monitor the
IPC calls. I'm trying to find out what caused the
ASAN bot failures by landing piecemeal (per discussion
with Joi).
The original CL was:
Support tracking of IPC messages as tasks in profiler
Also started to do more cleanup, including creating
a base/profiler directory, and moving parts of the
over-sized tracked_objects.* into that directory.
r=rtenneti
Review URL: http://codereview.chromium.org/8480014
But this CL is:
TBR=joi
Review URL: http://codereview.chromium.org/8499022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@109040 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/profiler')
-rw-r--r-- | base/profiler/scoped_profile.cc | 31 | ||||
-rw-r--r-- | base/profiler/scoped_profile.h | 47 | ||||
-rw-r--r-- | base/profiler/tracked_time.cc | 80 | ||||
-rw-r--r-- | base/profiler/tracked_time.h | 84 | ||||
-rw-r--r-- | base/profiler/tracked_time_unittest.cc | 111 |
5 files changed, 353 insertions, 0 deletions
diff --git a/base/profiler/scoped_profile.cc b/base/profiler/scoped_profile.cc new file mode 100644 index 0000000..7bd31fe --- /dev/null +++ b/base/profiler/scoped_profile.cc @@ -0,0 +1,31 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/profiler/scoped_profile.h" + +#include "base/location.h" +#include "base/tracked_objects.h" + + +namespace tracked_objects { + + +ScopedProfile::ScopedProfile(const Location& location) + : birth_(ThreadData::TallyABirthIfActive(location)), + start_of_run_(ThreadData::Now()) { +} + +ScopedProfile::~ScopedProfile() { + StopClockAndTally(); +} + +void ScopedProfile::StopClockAndTally() { + if (!birth_) + return; + ThreadData::TallyRunInAScopedRegionIfTracking(birth_, start_of_run_, + ThreadData::Now()); + birth_ = NULL; +} + +} // namespace tracked_objects diff --git a/base/profiler/scoped_profile.h b/base/profiler/scoped_profile.h new file mode 100644 index 0000000..2754f5e --- /dev/null +++ b/base/profiler/scoped_profile.h @@ -0,0 +1,47 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + + +#ifndef BASE_PROFILER_SCOPED_PROFILE_H_ +#define BASE_PROFILER_SCOPED_PROFILE_H_ + +//------------------------------------------------------------------------------ +// ScopedProfile provides basic helper functions for profiling a short +// region of code within a scope. It is separate from the related ThreadData +// class so that it can be included without much other cruft, and provide the +// macros listed below. + +#include "base/base_export.h" +#include "base/location.h" +#include "base/profiler/tracked_time.h" + +#define TRACK_RUN_IN_THIS_SCOPED_REGION_FOR_OFFICIAL_BUILDS(variable_name) \ + ::tracked_objects::ScopedProfile variable_name(FROM_HERE) + +#define TRACK_RUN_IN_IPC_HANDLER(dispatch_function_name) \ + ::tracked_objects::ScopedProfile some_tracking_variable_name( \ + FROM_HERE_WITH_EXPLICIT_FUNCTION(#dispatch_function_name)) + + +namespace tracked_objects { +class Births; + +class BASE_EXPORT ScopedProfile { + public: + explicit ScopedProfile(const Location& location); + ~ScopedProfile(); + + // Stop tracing prior to the end destruction of the instance. + void StopClockAndTally(); + + private: + Births* birth_; // Place in code where tracking started. + const TrackedTime start_of_run_; + + DISALLOW_COPY_AND_ASSIGN(ScopedProfile); +}; + +} // namespace tracked_objects + +#endif // BASE_PROFILER_SCOPED_PROFILE_H_ diff --git a/base/profiler/tracked_time.cc b/base/profiler/tracked_time.cc new file mode 100644 index 0000000..0e227bd --- /dev/null +++ b/base/profiler/tracked_time.cc @@ -0,0 +1,80 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/profiler/tracked_time.h" + +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <mmsystem.h> // Declare timeGetTime()... after including build_config. +#endif + +namespace tracked_objects { + +#if defined(USE_FAST_TIME_CLASS_FOR_DURATION_CALCULATIONS) + +Duration::Duration() : ms_(0) {} +Duration::Duration(int32 duration) : ms_(duration) {} + +Duration& Duration::operator+=(const Duration& other) { + ms_ += other.ms_; + return *this; +} + +Duration Duration::operator+(const Duration& other) const { + return Duration(ms_ + other.ms_); +} + +bool Duration::operator==(const Duration& other) const { + return ms_ == other.ms_; +} + +bool Duration::operator!=(const Duration& other) const { + return ms_ != other.ms_; +} + +bool Duration::operator>(const Duration& other) const { + return ms_ > other.ms_; +} + +// static +Duration Duration::FromMilliseconds(int ms) { return Duration(ms); } + +int32 Duration::InMilliseconds() const { return ms_; } + +//------------------------------------------------------------------------------ + +TrackedTime::TrackedTime() : ms_(0) {} +TrackedTime::TrackedTime(int32 ms) : ms_(ms) {} +TrackedTime::TrackedTime(const base::TimeTicks& time) + : ms_((time - base::TimeTicks()).InMilliseconds()) { +} + +// static +TrackedTime TrackedTime::Now() { +#if defined(OS_WIN) + // Use lock-free accessor to 32 bit time. + // Note that TimeTicks::Now() is built on this, so we have "compatible" + // times when we down-convert a TimeTicks sample. + // TODO(jar): Surface this interface via something in base/time.h. + return TrackedTime(static_cast<int32>(timeGetTime())); +#else + // Posix has nice cheap 64 bit times, so we just down-convert it. + return TrackedTime(base::TimeTicks::Now()); +#endif // OS_WIN +} + +Duration TrackedTime::operator-(const TrackedTime& other) const { + return Duration(ms_ - other.ms_); +} + +TrackedTime TrackedTime::operator+(const Duration& other) const { + return TrackedTime(ms_ + other.ms_); +} + +bool TrackedTime::is_null() const { return ms_ == 0; } + +#endif // USE_FAST_TIME_CLASS_FOR_DURATION_CALCULATIONS + +} // namespace tracked_objects diff --git a/base/profiler/tracked_time.h b/base/profiler/tracked_time.h new file mode 100644 index 0000000..e8e6d17 --- /dev/null +++ b/base/profiler/tracked_time.h @@ -0,0 +1,84 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_PROFILER_TRACKED_TIME_H_ +#define BASE_PROFILER_TRACKED_TIME_H_ + + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/time.h" + +namespace tracked_objects { + +//------------------------------------------------------------------------------ + +#define USE_FAST_TIME_CLASS_FOR_DURATION_CALCULATIONS + +#if defined(USE_FAST_TIME_CLASS_FOR_DURATION_CALCULATIONS) + +// TimeTicks maintains a wasteful 64 bits of data (we need less than 32), and on +// windows, a 64 bit timer is expensive to even obtain. We use a simple +// millisecond counter for most of our time values, as well as millisecond units +// of duration between those values. This means we can only handle durations +// up to 49 days (range), or 24 days (non-negative time durations). +// We only define enough methods to service the needs of the tracking classes, +// and our interfaces are modeled after what TimeTicks and TimeDelta use (so we +// can swap them into place if we want to use the "real" classes). + +class BASE_EXPORT Duration { // Similar to base::TimeDelta. + public: + Duration(); + + Duration& operator+=(const Duration& other); + Duration operator+(const Duration& other) const; + + bool operator==(const Duration& other) const; + bool operator!=(const Duration& other) const; + bool operator>(const Duration& other) const; + + static Duration FromMilliseconds(int ms); + + int32 InMilliseconds() const; + + private: + friend class TrackedTime; + explicit Duration(int32 duration); + + // Internal time is stored directly in milliseconds. + int32 ms_; +}; + +class BASE_EXPORT TrackedTime { // Similar to base::TimeTicks. + public: + TrackedTime(); + explicit TrackedTime(const base::TimeTicks& time); + + static TrackedTime Now(); + Duration operator-(const TrackedTime& other) const; + TrackedTime operator+(const Duration& other) const; + bool is_null() const; + + private: + friend class Duration; + explicit TrackedTime(int32 ms); + + // Internal duration is stored directly in milliseconds. + uint32 ms_; +}; + +#else + +// Just use full 64 bit time calculations, and the slower TimeTicks::Now(). +// This allows us (as an alternative) to test with larger ranges of times, and +// with a more thoroughly tested class. + +typedef base::TimeTicks TrackedTime; +typedef base::TimeDelta Duration; + +#endif // USE_FAST_TIME_CLASS_FOR_DURATION_CALCULATIONS + +} // namespace tracked_objects + +#endif // BASE_PROFILER_TRACKED_TIME_H_ diff --git a/base/profiler/tracked_time_unittest.cc b/base/profiler/tracked_time_unittest.cc new file mode 100644 index 0000000..fee4ba6 --- /dev/null +++ b/base/profiler/tracked_time_unittest.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test of classes in tracked_time.cc + +#include "base/profiler/tracked_time.h" +#include "base/time.h" +#include "base/tracked_objects.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace tracked_objects { + +TEST(TrackedTimeTest, TrackedTimerMilliseconds) { + // First make sure we basicallly transfer simple milliseconds values as + // expected. Most critically, things should not become null. + int32 kSomeMilliseconds = 243; // Some example times. + int64 kReallyBigMilliseconds = (1LL << 35) + kSomeMilliseconds; + + TrackedTime some = TrackedTime() + + Duration::FromMilliseconds(kSomeMilliseconds); + EXPECT_EQ(kSomeMilliseconds, (some - TrackedTime()).InMilliseconds()); + EXPECT_FALSE(some.is_null()); + + // Now create a big time, to check that it is wrapped modulo 2^32. + base::TimeTicks big = base::TimeTicks() + + base::TimeDelta::FromMilliseconds(kReallyBigMilliseconds); + EXPECT_EQ(kReallyBigMilliseconds, (big - base::TimeTicks()).InMilliseconds()); + + TrackedTime wrapped_big(big); +#if defined(USE_FAST_TIME_CLASS_FOR_DURATION_CALCULATIONS) + // Expect wrapping at 32 bits. + EXPECT_EQ(kSomeMilliseconds, (wrapped_big - TrackedTime()).InMilliseconds()); +#else // !USE_FAST_TIME_CLASS_FOR_DURATION_CALCULATIONS) + // Expect no wrapping at 32 bits. + EXPECT_EQ(kReallyBigMilliseconds, + (wrapped_big - TrackedTime()).InMilliseconds()); +#endif // USE_FAST_TIME_CLASS_FOR_DURATION_CALCULATIONS) +} + +TEST(TrackedTimeTest, TrackedTimerDuration) { + int kFirstMilliseconds = 793; + int kSecondMilliseconds = 14889; + + Duration first = Duration::FromMilliseconds(kFirstMilliseconds); + Duration second = Duration::FromMilliseconds(kSecondMilliseconds); + + EXPECT_EQ(kFirstMilliseconds, first.InMilliseconds()); + EXPECT_EQ(kSecondMilliseconds, second.InMilliseconds()); + + Duration sum = first + second; + EXPECT_EQ(kFirstMilliseconds + kSecondMilliseconds, sum.InMilliseconds()); +} + +TEST(TrackedTimeTest, TrackedTimerVsTimeTicks) { + // Make sure that our 32 bit timer is aligned with the TimeTicks() timer. + + // First get a 64 bit timer (which should not be null). + base::TimeTicks ticks_before = base::TimeTicks::Now(); + EXPECT_FALSE(ticks_before.is_null()); + + // Then get a 32 bit timer that can be be null when it wraps. + TrackedTime now = TrackedTime::Now(); + + // Then get a bracketing time. + base::TimeTicks ticks_after = base::TimeTicks::Now(); + EXPECT_FALSE(ticks_after.is_null()); + + // Now make sure that we bracketed our tracked time nicely. + Duration before = now - TrackedTime(ticks_before); + EXPECT_LE(0, before.InMilliseconds()); + Duration after = now - TrackedTime(ticks_after); + EXPECT_GE(0, after.InMilliseconds()); +} + +TEST(TrackedTimeTest, TrackedTimerDisabled) { + // Check to be sure disabling the collection of data induces a null time + // (which we know will return much faster). + if (!ThreadData::InitializeAndSetTrackingStatus(false)) + return; + // Since we disabled tracking, we should get a null response. + TrackedTime track_now = ThreadData::Now(); + EXPECT_TRUE(track_now.is_null()); +} + +TEST(TrackedTimeTest, TrackedTimerEnabled) { + if (!ThreadData::InitializeAndSetTrackingStatus(true)) + return; + // Make sure that when we enable tracking, we get a real timer result. + + // First get a 64 bit timer (which should not be null). + base::TimeTicks ticks_before = base::TimeTicks::Now(); + EXPECT_FALSE(ticks_before.is_null()); + + // Then get a 32 bit timer that can be null when it wraps. + // Crtical difference from the TrackedTimerVsTimeTicks test, is that we use + // ThreadData::Now(). It can sometimes return the null time. + TrackedTime now = ThreadData::Now(); + + // Then get a bracketing time. + base::TimeTicks ticks_after = base::TimeTicks::Now(); + EXPECT_FALSE(ticks_after.is_null()); + + // Now make sure that we bracketed our tracked time nicely. + Duration before = now - TrackedTime(ticks_before); + EXPECT_LE(0, before.InMilliseconds()); + Duration after = now - TrackedTime(ticks_after); + EXPECT_GE(0, after.InMilliseconds()); +} + +} // namespace tracked_objects |