Bug 1476368 - Add VecHelper::take/take_and_preallocate. r=gw
authorNicolas Silva <nsilva@mozilla.com>
Tue, 19 Feb 2019 17:53:31 +0100
changeset 518594 7102801e2ca85f305f1d62371228d828f9d0f502
parent 518593 9af23e1d86c8b70beeea117eb3c68d02e7966ae2
child 518595 885c75c731bfc6172c699aee3cc8981d2f46df35
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1476368
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1476368 - Add VecHelper::take/take_and_preallocate. r=gw
gfx/wr/webrender/src/intern.rs
gfx/wr/webrender/src/render_backend.rs
gfx/wr/webrender/src/util.rs
--- a/gfx/wr/webrender/src/intern.rs
+++ b/gfx/wr/webrender/src/intern.rs
@@ -307,18 +307,18 @@ where
 
         handle
     }
 
     /// Retrieve the pending list of updates for an interner
     /// that need to be applied to the data store. Also run
     /// a GC step that removes old entries.
     pub fn end_frame_and_get_pending_updates(&mut self) -> UpdateList<S> {
-        let mut updates = mem::replace(&mut self.updates, Vec::new());
-        let data = mem::replace(&mut self.update_data, Vec::new());
+        let mut updates = self.updates.take_and_preallocate();
+        let data = self.update_data.take_and_preallocate();
 
         let free_list = &mut self.free_list;
         let current_epoch = self.current_epoch.0;
 
         // First, run a GC step. Walk through the handles, and
         // if we find any that haven't been used for some time,
         // remove them. If this ever shows up in profiles, we
         // can make the GC step partial (scan only part of the
@@ -336,17 +336,16 @@ where
                     index: handle.index as usize,
                     kind: UpdateKind::Remove,
                 });
                 return false;
             }
 
             true
         });
-
         let updates = UpdateList {
             updates,
             data,
         };
 
         // Begin the next epoch
         self.current_epoch = Epoch(self.current_epoch.0 + 1);
 
--- a/gfx/wr/webrender/src/render_backend.rs
+++ b/gfx/wr/webrender/src/render_backend.rs
@@ -49,24 +49,23 @@ use scene_builder::*;
 #[cfg(feature = "serialize")]
 use serde::{Serialize, Deserialize};
 #[cfg(feature = "debugger")]
 use serde_json;
 #[cfg(any(feature = "capture", feature = "replay"))]
 use std::path::PathBuf;
 use std::sync::Arc;
 use std::sync::atomic::{AtomicUsize, Ordering};
-use std::mem::replace;
 use std::sync::mpsc::{channel, Sender, Receiver};
 use std::time::{UNIX_EPOCH, SystemTime};
 use std::u32;
 #[cfg(feature = "replay")]
 use tiling::Frame;
 use time::precise_time_ns;
-use util::{Recycler, drain_filter};
+use util::{Recycler, VecHelper, drain_filter};
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Clone)]
 pub struct DocumentView {
     pub window_size: DeviceIntSize,
     pub inner_rect: DeviceIntRect,
     pub layer: DocumentLayer,
@@ -565,17 +564,17 @@ impl Document {
                 &self.clip_scroll_tree,
                 &self.data_stores.clip,
             ));
             self.hit_tester_is_valid = true;
         }
     }
 
     pub fn updated_pipeline_info(&mut self) -> PipelineInfo {
-        let removed_pipelines = replace(&mut self.removed_pipelines, Vec::new());
+        let removed_pipelines = self.removed_pipelines.take_and_preallocate();
         PipelineInfo {
             epochs: self.scene.pipeline_epochs.clone(),
             removed_pipelines,
         }
     }
 
     pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
         self.clip_scroll_tree
@@ -890,28 +889,28 @@ impl RenderBackend {
                             // always forwarded to the scene builder thread to avoid this case.
                             if let Some(tx) = result_tx {
                                 tx.send(SceneSwapResult::Aborted).unwrap();
                             }
                             continue;
                         }
 
                         self.resource_cache.add_rasterized_blob_images(
-                            replace(&mut txn.rasterized_blobs, Vec::new())
+                            txn.rasterized_blobs.take()
                         );
                         if let Some((rasterizer, info)) = txn.blob_rasterizer.take() {
                             self.resource_cache.set_blob_rasterizer(rasterizer, info);
                         }
 
                         self.update_document(
                             txn.document_id,
-                            replace(&mut txn.resource_updates, Vec::new()),
+                            txn.resource_updates.take(),
                             txn.interner_updates.take(),
-                            replace(&mut txn.frame_ops, Vec::new()),
-                            replace(&mut txn.notifications, Vec::new()),
+                            txn.frame_ops.take(),
+                            txn.notifications.take(),
                             txn.render_frame,
                             txn.invalidate_rendered_frame,
                             &mut frame_counter,
                             &mut profile_counters,
                             has_built_scene,
                         );
                     },
                     SceneBuilderResult::FlushComplete(tx) => {
@@ -1247,20 +1246,20 @@ impl RenderBackend {
         }
 
         if !transaction_msg.use_scene_builder_thread &&
             txn.can_skip_scene_builder() &&
             txn.blob_rasterizer.is_none() {
 
             self.update_document(
                 txn.document_id,
-                replace(&mut txn.resource_updates, Vec::new()),
+                txn.resource_updates.take(),
                 None,
-                replace(&mut txn.frame_ops, Vec::new()),
-                replace(&mut txn.notifications, Vec::new()),
+                txn.frame_ops.take(),
+                txn.notifications.take(),
                 txn.render_frame,
                 txn.invalidate_rendered_frame,
                 frame_counter,
                 profile_counters,
                 false
             );
 
             return;
--- a/gfx/wr/webrender/src/util.rs
+++ b/gfx/wr/webrender/src/util.rs
@@ -8,16 +8,17 @@ use euclid::{Point2D, Rect, Size2D, Type
 use euclid::{TypedTransform2D, TypedTransform3D, TypedVector2D, TypedScale};
 use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps};
 use num_traits::Zero;
 use plane_split::{Clipper, Polygon};
 use std::{i32, f32, fmt, ptr};
 use std::borrow::Cow;
 use std::os::raw::c_void;
 use std::sync::Arc;
+use std::mem::replace;
 
 
 // Matches the definition of SK_ScalarNearlyZero in Skia.
 const NEARLY_ZERO: f32 = 1.0 / 4096.0;
 
 /// A typesafe helper that separates new value construction from
 /// vector growing, allowing LLVM to ideally construct the element in place.
 pub struct Allocation<'a, T: 'a> {
@@ -56,16 +57,24 @@ impl<'a, T> VecEntry<'a, T> {
 }
 
 pub trait VecHelper<T> {
     /// Growns the vector by a single entry, returning the allocation.
     fn alloc(&mut self) -> Allocation<T>;
     /// Either returns an existing elemenet, or grows the vector by one.
     /// Doesn't expect indices to be higher than the current length.
     fn entry(&mut self, index: usize) -> VecEntry<T>;
+
+    /// Equivalent to `mem::replace(&mut vec, Vec::new())`
+    fn take(&mut self) -> Self;
+
+    /// Functionally equivalent to `mem::replace(&mut vec, Vec::new())` but tries
+    /// to keep the allocation in the caller if it is empty or replace it with a
+    /// pre-allocated vector.
+    fn take_and_preallocate(&mut self) -> Self;
 }
 
 impl<T> VecHelper<T> for Vec<T> {
     fn alloc(&mut self) -> Allocation<T> {
         let index = self.len();
         if self.capacity() == index {
             self.reserve(1);
         }
@@ -80,16 +89,29 @@ impl<T> VecHelper<T> for Vec<T> {
             VecEntry::Occupied(unsafe {
                 self.get_unchecked_mut(index)
             })
         } else {
             assert_eq!(index, self.len());
             VecEntry::Vacant(self.alloc())
         }
     }
+
+    fn take(&mut self) -> Self {
+        replace(self, Vec::new())
+    }
+
+    fn take_and_preallocate(&mut self) -> Self {
+        let len = self.len();
+        if len == 0 {
+            self.clear();
+            return Vec::new();
+        }
+        replace(self, Vec::with_capacity(len + 8))
+    }
 }
 
 
 // Represents an optimized transform where there is only
 // a scale and translation (which are guaranteed to maintain
 // an axis align rectangle under transformation). The
 // scaling is applied first, followed by the translation.
 // TODO(gw): We should try and incorporate F <-> T units here,