Bug 1382440 - Fix CPUUsageWatcher on OSX and Linux r=froydnj

Properly enclose all relevant details of CPUUsageWatcher in ifdefs
which control whether it should be active or not. Additionally,
apparently clock_gettime is not defined on OSX prior to 10.12, so
this is failing to compile for OSX on the build server, but not
locally. However, clock_get_time and getrusage should cover our
use cases sufficiently.

MozReview-Commit-ID: Ffi6yXLb9gO

--HG--
extra : rebase_source : 84f9cf3b2074883dc6fe6d5a50ff27ffdb008a4f
This commit is contained in:
Doug Thayer 2017-08-28 14:00:22 -07:00
Родитель 8aae071723
Коммит 2e2f55c74a
2 изменённых файлов: 70 добавлений и 30 удалений

Просмотреть файл

@ -9,18 +9,15 @@
#include "prsystem.h"
#ifdef XP_MACOSX
#include <sys/resource.h>
#include <mach/clock.h>
#include <mach/mach_host.h>
#endif
// We only support OSX and Windows, because on Linux we're forced to read
// from /proc/stat in order to get global CPU values. We would prefer to not
// eat that cost for this.
#if defined(NIGHTLY_BUILD) && (defined(XP_WIN) || defined(XP_MACOSX))
#define CPU_USAGE_WATCHER_ACTIVE
#endif
namespace mozilla {
#ifdef CPU_USAGE_WATCHER_ACTIVE
// Even if the machine only has one processor, tolerate up to 50%
// external CPU usage.
static const float kTolerableExternalCPUUsageFloor = 0.5f;
@ -37,26 +34,44 @@ struct CPUStats {
#ifdef XP_MACOSX
static const uint64_t kNanosecondsPerSecond = 1000000000LL;
static const uint64_t kCPUCheckInterval = kNanosecondsPerSecond / 2LL;
static const uint64_t kMicrosecondsPerSecond = 1000000LL;
static const uint64_t kNanosecondsPerMicrosecond = 1000LL;
static const uint64_t kCPUCheckInterval = kMicrosecondsPerSecond / 2LL;
Result<uint64_t, CPUUsageWatcherError>
GetClockTime(clockid_t clockId) {
timespec clockResult;
bool success = !clock_gettime(clockId, &clockResult);
if (!success) {
return Err(ClockGetTimeError);
}
return ((uint64_t)clockResult.tv_sec) * kNanosecondsPerSecond +
(uint64_t)clockResult.tv_nsec;
uint64_t GetMicroseconds(timeval time) {
return ((uint64_t)time.tv_sec) * kMicrosecondsPerSecond +
(uint64_t)time.tv_usec;
}
uint64_t GetMicroseconds(mach_timespec_t time) {
return ((uint64_t)time.tv_sec) * kMicrosecondsPerSecond +
((uint64_t)time.tv_nsec) / kNanosecondsPerMicrosecond;
}
Result<CPUStats, CPUUsageWatcherError>
GetProcessCPUStats(int32_t numCPUs) {
CPUStats result = {};
MOZ_TRY_VAR(result.usageTime, GetClockTime(CLOCK_PROCESS_CPUTIME_ID));
MOZ_TRY_VAR(result.updateTime, GetClockTime(CLOCK_MONOTONIC));
// CLOCK_PROCESS_CPUTIME_ID will give us the sum of the values across all
rusage usage;
int32_t rusageResult = getrusage(RUSAGE_SELF, &usage);
if (rusageResult == -1) {
return Err(GetProcessTimesError);
}
result.usageTime = GetMicroseconds(usage.ru_utime) + GetMicroseconds(usage.ru_stime);
clock_serv_t realtimeClock;
kern_return_t errorResult =
host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &realtimeClock);
if (errorResult != KERN_SUCCESS) {
return Err(GetProcessTimesError);
}
mach_timespec_t time;
errorResult = clock_get_time(realtimeClock, &time);
if (errorResult != KERN_SUCCESS) {
return Err(GetProcessTimesError);
}
result.updateTime = GetMicroseconds(time);
// getrusage will give us the sum of the values across all
// of our cores. Divide by the number of CPUs to get an average.
result.usageTime /= numCPUs;
return result;
@ -157,8 +172,6 @@ CPUUsageWatcher::Init()
mExternalUsageThreshold = std::max(1.0f - 1.0f / (float)mNumCPUs,
kTolerableExternalCPUUsageFloor);
#ifdef CPU_USAGE_WATCHER_ACTIVE
CPUStats processTimes;
MOZ_TRY_VAR(processTimes, GetProcessCPUStats(mNumCPUs));
mProcessUpdateTime = processTimes.updateTime;
@ -176,18 +189,16 @@ CPUUsageWatcher::Init()
NS_NewRunnableFunction("CPUUsageWatcher::Init",
[=]() { HangMonitor::RegisterAnnotator(*self); }));
#endif // CPU_USAGE_WATCHER_ACTIVE
return Ok();
}
void
CPUUsageWatcher::Uninit()
{
if (mInitialized) {
HangMonitor::UnregisterAnnotator(*this);
}
mInitialized = false;
#ifdef CPU_USAGE_WATCHER_ACTIVE
HangMonitor::UnregisterAnnotator(*this);
#endif // CPU_USAGE_WATCHER_ACTIVE
}
Result<Ok, CPUUsageWatcherError>
@ -197,7 +208,6 @@ CPUUsageWatcher::CollectCPUUsage()
return Ok();
}
#ifdef CPU_USAGE_WATCHER_ACTIVE
mExternalUsageRatio = 0.0f;
CPUStats processTimes;
@ -224,7 +234,6 @@ CPUUsageWatcher::CollectCPUUsage()
mExternalUsageRatio = std::max(0.0f,
globalUsageNormalized - processUsageNormalized);
#endif // CPU_USAGE_WATCHER_ACTIVE
return Ok();
}
@ -240,4 +249,24 @@ CPUUsageWatcher::AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) {
}
}
#else // !CPU_USAGE_WATCHER_ACTIVE
Result<Ok, CPUUsageWatcherError>
CPUUsageWatcher::Init()
{
return Ok();
}
void CPUUsageWatcher::Uninit() {}
Result<Ok, CPUUsageWatcherError>
CPUUsageWatcher::CollectCPUUsage()
{
return Ok();
}
void CPUUsageWatcher::AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) {}
#endif // CPU_USAGE_WATCHER_ACTIVE
} // namespace mozilla

Просмотреть файл

@ -11,6 +11,13 @@
#include "mozilla/HangAnnotations.h"
// We only support OSX and Windows, because on Linux we're forced to read
// from /proc/stat in order to get global CPU values. We would prefer to not
// eat that cost for this.
#if defined(NIGHTLY_BUILD) && (defined(XP_WIN) || defined(XP_MACOSX))
#define CPU_USAGE_WATCHER_ACTIVE
#endif
namespace mozilla {
enum CPUUsageWatcherError : uint8_t
@ -33,6 +40,7 @@ class CPUUsageWatcher
: public HangMonitor::Annotator
{
public:
#ifdef CPU_USAGE_WATCHER_ACTIVE
CPUUsageWatcher()
: mInitialized(false)
, mExternalUsageThreshold(0)
@ -42,6 +50,7 @@ public:
, mGlobalUsageTime(0)
, mGlobalUpdateTime(0)
{}
#endif
Result<Ok, CPUUsageWatcherError> Init();
@ -54,6 +63,7 @@ public:
void AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) final;
private:
#ifdef CPU_USAGE_WATCHER_ACTIVE
bool mInitialized;
// The threshold above which we will mark a hang as occurring under high
// external CPU usage conditions
@ -75,6 +85,7 @@ private:
uint64_t mGlobalUpdateTime;
// The number of virtual cores on our machine
uint64_t mNumCPUs;
#endif
};
} // namespace mozilla