diff options
author | David Teller <dteller@mozilla.com> | 2019-01-28 23:41:20 +0100 |
---|---|---|
committer | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-01-28 23:41:20 +0100 |
commit | 3476c1d60ec29c5497123194acd7a9310b1023d2 (patch) | |
tree | 4933db7b4bb27893d3511ac21d5d04a11deea6a9 | |
parent | e82fdef9c7bed415d004086740cab57211575511 (diff) | |
download | UXP-3476c1d60ec29c5497123194acd7a9310b1023d2.tar UXP-3476c1d60ec29c5497123194acd7a9310b1023d2.tar.gz UXP-3476c1d60ec29c5497123194acd7a9310b1023d2.tar.lz UXP-3476c1d60ec29c5497123194acd7a9310b1023d2.tar.xz UXP-3476c1d60ec29c5497123194acd7a9310b1023d2.zip |
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.
-rw-r--r-- | js/src/jsapi.h | 2 | ||||
-rw-r--r-- | js/src/vm/Stopwatch.cpp | 24 | ||||
-rw-r--r-- | toolkit/components/perfmonitoring/nsPerformanceStats.cpp | 8 | ||||
-rw-r--r-- | toolkit/components/perfmonitoring/nsPerformanceStats.h | 2 |
4 files changed, 25 insertions, 11 deletions
diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 0983f034f..799396a0a 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -6566,7 +6566,7 @@ struct JS_PUBLIC_API(PerformanceGroup) { 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. diff --git a/js/src/vm/Stopwatch.cpp b/js/src/vm/Stopwatch.cpp index 7a6acb970..49b70c478 100644 --- a/js/src/vm/Stopwatch.cpp +++ b/js/src/vm/Stopwatch.cpp @@ -136,6 +136,9 @@ PerformanceMonitoring::start() bool PerformanceMonitoring::commit() { + // Maximum initialization size, in elements for the vector of groups. + static const size_t MAX_GROUPS_INIT_CAPACITY = 1024; + #if !defined(MOZ_HAVE_RDTSC) // The AutoStopwatch is only executed if `MOZ_HAVE_RDTSC`. return false; @@ -152,12 +155,19 @@ PerformanceMonitoring::commit() return true; } - PerformanceGroupVector recentGroups; - recentGroups_.swap(recentGroups); + // The move operation is generally constant time, unless `recentGroups_.length()` is very small, in which case it's + // fast anyway because it's small. + PerformanceGroupVector recentGroups(Move(recentGroups_)); + recentGroups_ = PerformanceGroupVector(); // Reconstruct after `Move`. bool success = true; - if (stopwatchCommitCallback) - success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure); + if (stopwatchCommitCallback) { + success = stopwatchCommitCallback(iteration_, recentGroups, stopwatchCommitClosure); + } + + // Heuristic use: we expect to have roughly the same number of groups as in the previous iteration. + const size_t capacity = std::min(recentGroups.capacity(), MAX_GROUPS_INIT_CAPACITY); + success = recentGroups_.reserve(capacity) && success; // 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 @@ -227,7 +237,7 @@ AutoStopwatch::AutoStopwatch(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IM MOZ_GUARD_OBJECT_NOTIFIER_INIT; JSCompartment* compartment = cx_->compartment(); - if (compartment->scheduledForDestruction) + if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) return; JSRuntime* runtime = cx_->runtime(); @@ -266,11 +276,11 @@ AutoStopwatch::~AutoStopwatch() } JSCompartment* compartment = cx_->compartment(); - if (compartment->scheduledForDestruction) + if (MOZ_UNLIKELY(compartment->scheduledForDestruction)) return; 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. // Any information we may have is obsolete. return; diff --git a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp index 6c470356a..03e63a461 100644 --- a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp +++ b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp @@ -1310,8 +1310,12 @@ nsPerformanceStatsService::GetResources(uint64_t* userTime, void 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) { // We are shutting down. return; diff --git a/toolkit/components/perfmonitoring/nsPerformanceStats.h b/toolkit/components/perfmonitoring/nsPerformanceStats.h index 6902c840d..661a78a1a 100644 --- a/toolkit/components/perfmonitoring/nsPerformanceStats.h +++ b/toolkit/components/perfmonitoring/nsPerformanceStats.h @@ -19,7 +19,7 @@ class nsPerformanceGroup; class nsPerformanceGroupDetails; -typedef mozilla::Vector<RefPtr<nsPerformanceGroup>> GroupVector; +typedef mozilla::Vector<RefPtr<nsPerformanceGroup>, 8> GroupVector; /** * A data structure for registering observers interested in |