mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-30 20:37:31 +09:00
Reduce number of allocations in AutoStopwatch
This patch fixes two related issues. 1. The AutoStopwatch uses a stack-allocated `mozilla::Vector` to communicate with its callback during each compartment switch. This vector was designed to allow its contents to be stack-allocated but they turned out to be accidentally heap-allocated. 2. During each tick, the stopwatch fills a vector `recentGroups_`. This vector always started with minimal capacity and had to grow repeatedly as groups were added, causing repeated reallocations. This patch preallocates `recentGroups_` to have the same capacity as the previous tick. We expect that this should eventually reach a stable size that closely matches the actual needs of the process.
This commit is contained in:
parent
dce38e8d76
commit
7d0bef1093
4 changed files with 31 additions and 9 deletions
|
|
@ -6566,7 +6566,7 @@ struct JS_PUBLIC_API(PerformanceGroup) {
|
||||||
uint64_t refCount_;
|
uint64_t refCount_;
|
||||||
};
|
};
|
||||||
|
|
||||||
using PerformanceGroupVector = mozilla::Vector<RefPtr<js::PerformanceGroup>, 0, SystemAllocPolicy>;
|
using PerformanceGroupVector = mozilla::Vector<RefPtr<js::PerformanceGroup>, 8, SystemAllocPolicy>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commit any Performance Monitoring data.
|
* Commit any Performance Monitoring data.
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include "gc/Zone.h"
|
#include "gc/Zone.h"
|
||||||
#include "vm/Runtime.h"
|
#include "vm/Runtime.h"
|
||||||
|
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -136,6 +137,9 @@ PerformanceMonitoring::start()
|
||||||
bool
|
bool
|
||||||
PerformanceMonitoring::commit()
|
PerformanceMonitoring::commit()
|
||||||
{
|
{
|
||||||
|
// Maximal initialization size, in elements for the vector of groups.
|
||||||
|
static const size_t MAX_GROUPS_INIT_CAPACITY = 1024;
|
||||||
|
|
||||||
#if !defined(MOZ_HAVE_RDTSC)
|
#if !defined(MOZ_HAVE_RDTSC)
|
||||||
// The AutoStopwatch is only executed if `MOZ_HAVE_RDTSC`.
|
// The AutoStopwatch is only executed if `MOZ_HAVE_RDTSC`.
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -152,13 +156,24 @@ PerformanceMonitoring::commit()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PerformanceGroupVector recentGroups;
|
// The move operation is generally constant time, unless
|
||||||
recentGroups_.swap(recentGroups);
|
// `recentGroups_.length()` is very small, in which case
|
||||||
|
// it's fast just because it's small.
|
||||||
|
PerformanceGroupVector recentGroups(Move(recentGroups_));
|
||||||
|
recentGroups_ = PerformanceGroupVector(); // Reconstruct after `Move`.
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
if (stopwatchCommitCallback)
|
if (stopwatchCommitCallback)
|
||||||
success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure);
|
success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure);
|
||||||
|
|
||||||
|
// Heuristic: we expect to have roughly the same number of groups as in
|
||||||
|
// the previous iteration.
|
||||||
|
const size_t capacity = recentGroups.capacity() < MAX_GROUPS_INIT_CAPACITY ?
|
||||||
|
recentGroups.capacity() :
|
||||||
|
MAX_GROUPS_INIT_CAPACITY;
|
||||||
|
success = recentGroups_.reserve(capacity)
|
||||||
|
&& success;
|
||||||
|
|
||||||
// Reset immediately, to make sure that we're not hit by the end
|
// Reset immediately, to make sure that we're not hit by the end
|
||||||
// of a nested event loop (which would cause `commit` to be called
|
// of a nested event loop (which would cause `commit` to be called
|
||||||
// twice in succession).
|
// twice in succession).
|
||||||
|
|
@ -227,7 +242,7 @@ AutoStopwatch::AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IM
|
||||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||||
|
|
||||||
JSCompartment* compartment = cx_->compartment();
|
JSCompartment* compartment = cx_->compartment();
|
||||||
if (compartment->scheduledForDestruction)
|
if (MOZ_UNLIKELY(compartment->scheduledForDestruction))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JSRuntime* runtime = cx_->runtime();
|
JSRuntime* runtime = cx_->runtime();
|
||||||
|
|
@ -266,11 +281,11 @@ AutoStopwatch::~AutoStopwatch()
|
||||||
}
|
}
|
||||||
|
|
||||||
JSCompartment* compartment = cx_->compartment();
|
JSCompartment* compartment = cx_->compartment();
|
||||||
if (compartment->scheduledForDestruction)
|
if (MOZ_UNLIKELY(compartment->scheduledForDestruction))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JSRuntime* runtime = cx_->runtime();
|
JSRuntime* runtime = cx_->runtime();
|
||||||
if (iteration_ != runtime->performanceMonitoring.iteration()) {
|
if (MOZ_UNLIKELY(iteration_ != runtime->performanceMonitoring.iteration())) {
|
||||||
// We have entered a nested event loop at some point.
|
// We have entered a nested event loop at some point.
|
||||||
// Any information we may have is obsolete.
|
// Any information we may have is obsolete.
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1082,6 +1082,9 @@ nsPerformanceStatsService::GetPerformanceGroups(JSContext* cx,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returning a vector that is too large would cause allocations all over the
|
||||||
|
// place in the JS engine. We want to be sure that all data is stored inline.
|
||||||
|
MOZ_ASSERT(out.length() <= out.sMaxInlineStorage);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1310,8 +1313,12 @@ nsPerformanceStatsService::GetResources(uint64_t* userTime,
|
||||||
|
|
||||||
void
|
void
|
||||||
nsPerformanceStatsService::NotifyJankObservers(const mozilla::Vector<uint64_t>& aPreviousJankLevels) {
|
nsPerformanceStatsService::NotifyJankObservers(const mozilla::Vector<uint64_t>& aPreviousJankLevels) {
|
||||||
GroupVector alerts;
|
|
||||||
mPendingAlerts.swap(alerts);
|
// The move operation is generally constant time, unless
|
||||||
|
// `mPendingAlerts.length()` is very small, in which case it's fast anyway.
|
||||||
|
GroupVector alerts(Move(mPendingAlerts));
|
||||||
|
mPendingAlerts = GroupVector(); // Reconstruct after `Move`.
|
||||||
|
|
||||||
if (!mPendingAlertsCollector) {
|
if (!mPendingAlertsCollector) {
|
||||||
// We are shutting down.
|
// We are shutting down.
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
class nsPerformanceGroup;
|
class nsPerformanceGroup;
|
||||||
class nsPerformanceGroupDetails;
|
class nsPerformanceGroupDetails;
|
||||||
|
|
||||||
typedef mozilla::Vector<RefPtr<nsPerformanceGroup>> GroupVector;
|
typedef mozilla::Vector<RefPtr<nsPerformanceGroup>, 8> GroupVector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data structure for registering observers interested in
|
* A data structure for registering observers interested in
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue