[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>
|
||||
#endif
|
||||
#if V8_OS_MACOSX
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
@ -25,6 +27,51 @@
|
||||
#include "src/base/logging.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 base {
|
||||
|
||||
@ -541,12 +588,7 @@ TimeTicks TimeTicks::HighResolutionNow() {
|
||||
#elif V8_OS_SOLARIS
|
||||
ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond);
|
||||
#elif V8_OS_POSIX
|
||||
struct timespec ts;
|
||||
int result = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
DCHECK_EQ(0, result);
|
||||
USE(result);
|
||||
ticks = (ts.tv_sec * Time::kMicrosecondsPerSecond +
|
||||
ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
|
||||
ticks = ClockNow(CLOCK_MONOTONIC);
|
||||
#endif // V8_OS_MACOSX
|
||||
// Make sure we never return 0 here.
|
||||
return TimeTicks(ticks + 1);
|
||||
@ -560,5 +602,30 @@ bool TimeTicks::IsHighResolutionClockWorking() {
|
||||
|
||||
#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 v8
|
||||
|
@ -360,7 +360,7 @@ class TimeTicks final : public time_internal::TimeBase<TimeTicks> {
|
||||
friend class time_internal::TimeBase<TimeTicks>;
|
||||
|
||||
// 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) {}
|
||||
};
|
||||
|
||||
@ -368,6 +368,31 @@ inline TimeTicks operator+(const TimeDelta& delta, const TimeTicks& ticks) {
|
||||
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 v8
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#endif
|
||||
|
||||
#include "src/base/platform/elapsed-timer.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
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 v8
|
||||
|
Loading…
Reference in New Issue
Block a user