[Reland] Implement CPU time for OS X and POSIX.
V8 tracing controller uses 2 clocks: wall clock and cpu clock. This patch implements CPU time for OS X and POSIX to provide more accurate accounting of CPU time used by each thread. BUG=v8:4984 LOG=n Review-Url: https://codereview.chromium.org/1966183003 Cr-Commit-Position: refs/heads/master@{#36213}
This commit is contained in:
parent
481502dad9
commit
efa27fb25e
@ -10,7 +10,9 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#if V8_OS_MACOSX
|
#if V8_OS_MACOSX
|
||||||
|
#include <mach/mach.h>
|
||||||
#include <mach/mach_time.h>
|
#include <mach/mach_time.h>
|
||||||
|
#include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -25,6 +27,51 @@
|
|||||||
#include "src/base/logging.h"
|
#include "src/base/logging.h"
|
||||||
#include "src/base/platform/platform.h"
|
#include "src/base/platform/platform.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#if V8_OS_MACOSX
|
||||||
|
int64_t ComputeThreadTicks() {
|
||||||
|
mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
|
||||||
|
thread_basic_info_data_t thread_info_data;
|
||||||
|
kern_return_t kr = thread_info(
|
||||||
|
pthread_mach_thread_np(pthread_self()),
|
||||||
|
THREAD_BASIC_INFO,
|
||||||
|
reinterpret_cast<thread_info_t>(&thread_info_data),
|
||||||
|
&thread_info_count);
|
||||||
|
CHECK(kr == KERN_SUCCESS);
|
||||||
|
|
||||||
|
v8::base::CheckedNumeric<int64_t> absolute_micros(
|
||||||
|
thread_info_data.user_time.seconds);
|
||||||
|
absolute_micros *= v8::base::Time::kMicrosecondsPerSecond;
|
||||||
|
absolute_micros += thread_info_data.user_time.microseconds;
|
||||||
|
return absolute_micros.ValueOrDie();
|
||||||
|
}
|
||||||
|
#elif V8_OS_POSIX
|
||||||
|
// Helper function to get results from clock_gettime() and convert to a
|
||||||
|
// microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported
|
||||||
|
// on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines
|
||||||
|
// _POSIX_MONOTONIC_CLOCK to -1.
|
||||||
|
inline int64_t ClockNow(clockid_t clk_id) {
|
||||||
|
#if (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
|
||||||
|
defined(V8_OS_BSD) || defined(V8_OS_ANDROID)
|
||||||
|
struct timespec ts;
|
||||||
|
if (clock_gettime(clk_id, &ts) != 0) {
|
||||||
|
UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
v8::base::internal::CheckedNumeric<int64_t> result(ts.tv_sec);
|
||||||
|
result *= v8::base::Time::kMicrosecondsPerSecond;
|
||||||
|
result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond);
|
||||||
|
return result.ValueOrDie();
|
||||||
|
#else // Monotonic clock not supported.
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif // V8_OS_MACOSX
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace base {
|
namespace base {
|
||||||
|
|
||||||
@ -541,12 +588,7 @@ TimeTicks TimeTicks::HighResolutionNow() {
|
|||||||
#elif V8_OS_SOLARIS
|
#elif V8_OS_SOLARIS
|
||||||
ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond);
|
ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond);
|
||||||
#elif V8_OS_POSIX
|
#elif V8_OS_POSIX
|
||||||
struct timespec ts;
|
ticks = ClockNow(CLOCK_MONOTONIC);
|
||||||
int result = clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
||||||
DCHECK_EQ(0, result);
|
|
||||||
USE(result);
|
|
||||||
ticks = (ts.tv_sec * Time::kMicrosecondsPerSecond +
|
|
||||||
ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
|
|
||||||
#endif // V8_OS_MACOSX
|
#endif // V8_OS_MACOSX
|
||||||
// Make sure we never return 0 here.
|
// Make sure we never return 0 here.
|
||||||
return TimeTicks(ticks + 1);
|
return TimeTicks(ticks + 1);
|
||||||
@ -560,5 +602,30 @@ bool TimeTicks::IsHighResolutionClockWorking() {
|
|||||||
|
|
||||||
#endif // V8_OS_WIN
|
#endif // V8_OS_WIN
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(lpy): For windows ThreadTicks implementation,
|
||||||
|
// see http://crbug.com/v8/5000
|
||||||
|
bool ThreadTicks::IsSupported() {
|
||||||
|
#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
|
||||||
|
defined(V8_OS_MACOSX) || defined(V8_OS_ANDROID)
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ThreadTicks ThreadTicks::Now() {
|
||||||
|
#if V8_OS_MACOSX
|
||||||
|
return ThreadTicks(ComputeThreadTicks());
|
||||||
|
#elif(defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
|
||||||
|
defined(V8_OS_ANDROID)
|
||||||
|
return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID));
|
||||||
|
#else
|
||||||
|
UNREACHABLE();
|
||||||
|
return ThreadTicks();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace base
|
} // namespace base
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -360,7 +360,7 @@ class TimeTicks final : public time_internal::TimeBase<TimeTicks> {
|
|||||||
friend class time_internal::TimeBase<TimeTicks>;
|
friend class time_internal::TimeBase<TimeTicks>;
|
||||||
|
|
||||||
// Please use Now() to create a new object. This is for internal use
|
// Please use Now() to create a new object. This is for internal use
|
||||||
// and testing. Ticks is in microseconds.
|
// and testing. Ticks are in microseconds.
|
||||||
explicit TimeTicks(int64_t ticks) : TimeBase(ticks) {}
|
explicit TimeTicks(int64_t ticks) : TimeBase(ticks) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -368,6 +368,31 @@ inline TimeTicks operator+(const TimeDelta& delta, const TimeTicks& ticks) {
|
|||||||
return ticks + delta;
|
return ticks + delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ThreadTicks ----------------------------------------------------------------
|
||||||
|
|
||||||
|
// Represents a clock, specific to a particular thread, than runs only while the
|
||||||
|
// thread is running.
|
||||||
|
class ThreadTicks final : public time_internal::TimeBase<ThreadTicks> {
|
||||||
|
public:
|
||||||
|
ThreadTicks() : TimeBase(0) {}
|
||||||
|
|
||||||
|
// Returns true if ThreadTicks::Now() is supported on this system.
|
||||||
|
static bool IsSupported();
|
||||||
|
|
||||||
|
// Returns thread-specific CPU-time on systems that support this feature.
|
||||||
|
// Needs to be guarded with a call to IsSupported(). Use this timer
|
||||||
|
// to (approximately) measure how much time the calling thread spent doing
|
||||||
|
// actual work vs. being de-scheduled. May return bogus results if the thread
|
||||||
|
// migrates to another CPU between two calls. Returns an empty ThreadTicks
|
||||||
|
// object until the initialization is completed.
|
||||||
|
static ThreadTicks Now();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// This is for internal use and testing. Ticks are in microseconds.
|
||||||
|
explicit ThreadTicks(int64_t ticks) : TimeBase(ticks) {}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace base
|
} // namespace base
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "src/base/platform/elapsed-timer.h"
|
#include "src/base/platform/elapsed-timer.h"
|
||||||
|
#include "src/base/platform/platform.h"
|
||||||
#include "testing/gtest/include/gtest/gtest.h"
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
@ -182,5 +183,32 @@ TEST(TimeTicks, IsMonotonic) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Disable on windows until it is implemented.
|
||||||
|
#if V8_OS_ANDROID || V8_OS_WIN
|
||||||
|
#define MAYBE_ThreadNow DISABLED_ThreadNow
|
||||||
|
#else
|
||||||
|
#define MAYBE_ThreadNow ThreadNow
|
||||||
|
#endif
|
||||||
|
TEST(ThreadTicks, MAYBE_ThreadNow) {
|
||||||
|
if (ThreadTicks::IsSupported()) {
|
||||||
|
TimeTicks begin = TimeTicks::Now();
|
||||||
|
ThreadTicks begin_thread = ThreadTicks::Now();
|
||||||
|
// Make sure that ThreadNow value is non-zero.
|
||||||
|
EXPECT_GT(begin_thread, ThreadTicks());
|
||||||
|
// Sleep for 10 milliseconds to get the thread de-scheduled.
|
||||||
|
OS::Sleep(base::TimeDelta::FromMilliseconds(10));
|
||||||
|
ThreadTicks end_thread = ThreadTicks::Now();
|
||||||
|
TimeTicks end = TimeTicks::Now();
|
||||||
|
TimeDelta delta = end - begin;
|
||||||
|
TimeDelta delta_thread = end_thread - begin_thread;
|
||||||
|
// Make sure that some thread time have elapsed.
|
||||||
|
EXPECT_GT(delta_thread.InMicroseconds(), 0);
|
||||||
|
// But the thread time is at least 9ms less than clock time.
|
||||||
|
TimeDelta difference = delta - delta_thread;
|
||||||
|
EXPECT_GE(difference.InMicroseconds(), 9000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace base
|
} // namespace base
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
Loading…
Reference in New Issue
Block a user