Bug 1648703 - Use a custom vector growth pattern in PrimitiveList. r=gw

This greatly reduces the number of vector reallocations happening while building primitive lists. On the difficult cases like youtube front page the reduction is a bit more than 50%, and more in other pages I tested. More importantly it dramatically reduces the amount of the most expensive of these reallocations which are when the vector is starting to get large.

Differential Revision: https://phabricator.services.mozilla.com/D81725
This commit is contained in:
Nicolas Silva 2020-07-01 07:01:18 +00:00
Родитель 957d144600
Коммит 36d0b0407a
1 изменённых файлов: 37 добавлений и 1 удалений

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

@ -4397,7 +4397,31 @@ impl PrimitiveList {
.intersection(&prim_rect)
.unwrap_or_else(LayoutRect::zero);
let instance_index = self.prim_instances.len();
// Primitive lengths aren't evenly distributed among primitive lists:
// We often have a large amount of single primitive lists, a
// few below 20~30 primitives, and even fewer lists (maybe a couple)
// in the multiple hundreds with nothing in between.
// We can see in profiles that reallocating vectors while pushing
// primitives is taking a large amount of the total scene build time,
// so we take advantage of what we know about the length distributions
// to go for an adapted vector growth pattern that avoids over-allocating
// for the many small allocations while avoiding a lot of reallocation by
// quickly converging to the common sizes.
// Rust's default vector growth strategy (when pushing elements one by one)
// is to double the capacity every time.
let prims_len = self.prim_instances.len();
if prims_len == self.prim_instances.capacity() {
let next_alloc = match prims_len {
1 ..= 31 => 32 - prims_len,
32 ..= 256 => 512 - prims_len,
_ => prims_len * 2,
};
self.prim_instances.reserve(next_alloc);
}
let instance_index = prims_len;
self.prim_instances.push(prim_instance);
if let Some(cluster) = self.clusters.last_mut() {
@ -4407,6 +4431,18 @@ impl PrimitiveList {
}
}
// Same idea with clusters, using a different distribution.
let clusters_len = self.clusters.len();
if clusters_len == self.clusters.capacity() {
let next_alloc = match clusters_len {
1 ..= 15 => 16 - clusters_len,
16 ..= 127 => 128 - clusters_len,
_ => clusters_len * 2,
};
self.clusters.reserve(next_alloc);
}
let mut cluster = PrimitiveCluster::new(
spatial_node_index,
flags,