mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-24 02:35:41 +00:00
Bug 1243241 - Make RDTSC monotonic. r=jandem
We assume that the total number of cycles spent executing JS code during an event is equal to the number of cycles in the "top group", i.e. a group to which everything belongs. While this is true in theory, RDTSC is actually non-monotonic, so we can end up with fewer cycles reported for the top group than for some groups whose execution was actually shorter. When we end up in this situation, groups with more cycles than the top group will be reported as using more CPU than was actually used. This patch fixes the situation by proxying RDTSC behind a trivial API that ensures that values are monotonic during each tick. --HG-- extra : transplant_source : %3E%8Aj%12e%B9%A7%08i%8Ef%28%F5%5D69q%15%8E%99
This commit is contained in:
parent
8402fc035a
commit
68a3dd828b
@ -40,6 +40,14 @@ PerformanceMonitoring::reset()
|
||||
// be overwritten progressively during the execution.
|
||||
++iteration_;
|
||||
recentGroups_.clear();
|
||||
|
||||
// Every so often, we will be rescheduled to another CPU. If this
|
||||
// happens, we may end up with an entirely unsynchronized
|
||||
// timestamp counter. If we do not reset
|
||||
// `highestTimestampCounter_`, we could end up ignoring entirely
|
||||
// valid sets of measures just because we are on a CPU that has a
|
||||
// lower RDTSC.
|
||||
highestTimestampCounter_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -158,6 +166,19 @@ PerformanceMonitoring::commit()
|
||||
return success;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
PerformanceMonitoring::monotonicReadTimestampCounter()
|
||||
{
|
||||
#if defined(MOZ_HAVE_RDTSC)
|
||||
const uint64_t hardware = ReadTimestampCounter();
|
||||
if (highestTimestampCounter_ < hardware)
|
||||
highestTimestampCounter_ = hardware;
|
||||
return highestTimestampCounter_;
|
||||
#else
|
||||
return 0;
|
||||
#endif // defined(MOZ_HAVE_RDTSC)
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceMonitoring::dispose(JSRuntime* rt)
|
||||
{
|
||||
@ -272,7 +293,7 @@ AutoStopwatch::enter()
|
||||
}
|
||||
|
||||
if (runtime->performanceMonitoring.isMonitoringJank()) {
|
||||
cyclesStart_ = this->getCycles();
|
||||
cyclesStart_ = this->getCycles(runtime);
|
||||
cpuStart_ = this->getCPU();
|
||||
isMonitoringJank_ = true;
|
||||
}
|
||||
@ -295,8 +316,8 @@ AutoStopwatch::exit()
|
||||
// limited.
|
||||
const cpuid_t cpuEnd = this->getCPU();
|
||||
if (isSameCPU(cpuStart_, cpuEnd)) {
|
||||
const uint64_t cyclesEnd = getCycles();
|
||||
cyclesDelta = getDelta(cyclesEnd, cyclesStart_);
|
||||
const uint64_t cyclesEnd = getCycles(runtime);
|
||||
cyclesDelta = cyclesEnd - cyclesStart_; // Always >= 0 by definition of `getCycles`.
|
||||
}
|
||||
#if WINVER >= 0x600
|
||||
updateTelemetry(cpuStart_, cpuEnd);
|
||||
@ -382,13 +403,9 @@ AutoStopwatch::getDelta(const uint64_t end, const uint64_t start) const
|
||||
}
|
||||
|
||||
uint64_t
|
||||
AutoStopwatch::getCycles() const
|
||||
AutoStopwatch::getCycles(JSRuntime* runtime) const
|
||||
{
|
||||
#if defined(MOZ_HAVE_RDTSC)
|
||||
return ReadTimestampCounter();
|
||||
#else
|
||||
return 0;
|
||||
#endif // defined(MOZ_HAVE_RDTSC)
|
||||
return runtime->performanceMonitoring.monotonicReadTimestampCounter();
|
||||
}
|
||||
|
||||
cpuid_t inline
|
||||
|
@ -85,6 +85,7 @@ struct PerformanceMonitoring {
|
||||
, isMonitoringCPOW_(false)
|
||||
, iteration_(0)
|
||||
, startedAtIteration_(0)
|
||||
, highestTimestampCounter_(0)
|
||||
{ }
|
||||
|
||||
/**
|
||||
@ -211,6 +212,13 @@ struct PerformanceMonitoring {
|
||||
*/
|
||||
uint64_t totalCPOWTime;
|
||||
|
||||
/**
|
||||
* A variant of RDTSC artificially made monotonic.
|
||||
*
|
||||
* Always return 0 on platforms that do not support RDTSC.
|
||||
*/
|
||||
uint64_t monotonicReadTimestampCounter();
|
||||
|
||||
/**
|
||||
* Data extracted by the AutoStopwatch to determine how often
|
||||
* we reschedule the process to a different CPU during the
|
||||
@ -285,6 +293,12 @@ struct PerformanceMonitoring {
|
||||
* Groups used in the current iteration.
|
||||
*/
|
||||
GroupVector recentGroups_;
|
||||
|
||||
/**
|
||||
* The highest value of the timestamp counter encountered
|
||||
* during this iteration.
|
||||
*/
|
||||
uint64_t highestTimestampCounter_;
|
||||
};
|
||||
|
||||
#if WINVER >= 0x0600
|
||||
@ -377,7 +391,7 @@ class AutoStopwatch final {
|
||||
|
||||
// Return the value of the Timestamp Counter, as provided by the CPU.
|
||||
// 0 on platforms for which we do not have access to a Timestamp Counter.
|
||||
uint64_t inline getCycles() const;
|
||||
uint64_t inline getCycles(JSRuntime*) const;
|
||||
|
||||
|
||||
// Return the identifier of the current CPU, on platforms for which we have
|
||||
|
Loading…
Reference in New Issue
Block a user