[librsvg: 4/5] PathBuilder: use a SmallVec while the path commands are being accumulated



commit ee63041d012406a9b05204ef604eb5411a8cf7ae
Author: Federico Mena Quintero <federico gnome org>
Date:   Tue Mar 24 16:52:20 2020 -0600

    PathBuilder: use a SmallVec while the path commands are being accumulated
    
    From the last commit, we had this for the big SVG file in #574:
    
    --------------------------------------------------------------------------------
      n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
    --------------------------------------------------------------------------------
     30 22,796,106,012    1,553,581,072    1,329,943,324   223,637,748            0
                                                           ^^^^^^^^^^^
    
    That extra-heap is a lot of allocator metadata or waste space,
    possibly from heap fragmentation due to all the realloc() shenanigans
    from using into_boxed_slice() on the starting Vec<PathCommand>.
    
    This commit makes PathBuilder use a SmallVec:
    
        pub struct PathBuilder {
            path_commands: SmallVec<[PathCommand; 32]>,
        }
    
    That is, it will keep up to 32 PathCommand directly inside itself, and
    only spill to a heap allocation if more elements come in.
    
    We still into_boxed_slice() for the final Path.  Hopefully this makes
    realloc() find heap blocks that are more closely packed.  Indeed:
    
    --------------------------------------------------------------------------------
      n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
    --------------------------------------------------------------------------------
     33 24,139,598,653    1,416,831,176    1,329,943,212    86,887,964            0
                                                            ^^^^^^^^^^
    
    That's a lot of less waste space.  Note also how the total bytes
    shrinks from 1,553,581,072 to 1,416,831,176.

 Cargo.lock                         |  1 +
 rsvg_internals/Cargo.toml          |  1 +
 rsvg_internals/src/path_builder.rs | 10 +++++++---
 3 files changed, 9 insertions(+), 3 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index a7ad5290..f1dd3655 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1366,6 +1366,7 @@ dependencies = [
  "rctree 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
diff --git a/rsvg_internals/Cargo.toml b/rsvg_internals/Cargo.toml
index 0dc8beef..6943e443 100644
--- a/rsvg_internals/Cargo.toml
+++ b/rsvg_internals/Cargo.toml
@@ -35,6 +35,7 @@ rayon = "1"
 rctree = "0.3.3"
 regex = "1"
 selectors = "0.22.0"
+smallvec = "1.2.0"
 url = "2"
 xml-rs = "0.8.0"
 
diff --git a/rsvg_internals/src/path_builder.rs b/rsvg_internals/src/path_builder.rs
index 7da68d3a..b5738ffb 100644
--- a/rsvg_internals/src/path_builder.rs
+++ b/rsvg_internals/src/path_builder.rs
@@ -1,5 +1,7 @@
 //! Representation of Bézier paths.
 
+use smallvec::SmallVec;
+
 use std::f64;
 use std::f64::consts::*;
 
@@ -294,9 +296,9 @@ impl PathCommand {
 ///
 /// When you are finished constructing a path builder, turn it into
 /// a `Path` with `into_path`.
-#[derive(Clone, Default)]
+#[derive(Clone)]
 pub struct PathBuilder {
-    path_commands: Vec<PathCommand>,
+    path_commands: SmallVec<[PathCommand; 32]>,
 }
 
 /// An immutable path
@@ -308,7 +310,9 @@ pub struct Path {
 
 impl PathBuilder {
     pub fn new() -> PathBuilder {
-        PathBuilder::default()
+        PathBuilder {
+            path_commands: SmallVec::new(),
+        }
     }
 
     pub fn into_path(self) -> Path {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]