summaryrefslogtreecommitdiffstats
path: root/js/src/vm
diff options
context:
space:
mode:
authorDavid Teller <dteller@mozilla.com>2019-01-28 23:41:20 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2019-01-28 23:41:20 +0100
commit3476c1d60ec29c5497123194acd7a9310b1023d2 (patch)
tree4933db7b4bb27893d3511ac21d5d04a11deea6a9 /js/src/vm
parente82fdef9c7bed415d004086740cab57211575511 (diff)
downloadUXP-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.
Diffstat (limited to 'js/src/vm')
-rw-r--r--js/src/vm/Stopwatch.cpp24
1 files changed, 17 insertions, 7 deletions
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;