Skip to content

Commit a0437c7

Browse files
committed
Use an unsafe serializer.
This gives a noticable impact on serialization performance in Gecko. wr_dp_push_text() goes from 35.6% of nsDisplayText::CreateWebRenderCommands down to 24%. The generated code is still pretty bad but hopefully adding proper noalias information to rust will fix that.
1 parent aa81aeb commit a0437c7

File tree

1 file changed

+53
-11
lines changed

1 file changed

+53
-11
lines changed

webrender_api/src/display_list.rs

+53-11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use YuvImageDisplayItem;
1717
use bincode;
1818
use serde::{Deserialize, Serialize, Serializer};
1919
use serde::ser::{SerializeMap, SerializeSeq};
20+
use std::io::Write;
21+
use std::{io, ptr};
2022
use std::marker::PhantomData;
2123
use time::precise_time_ns;
2224

@@ -483,6 +485,48 @@ impl<'a, 'b> Serialize for DisplayItemRef<'a, 'b> {
483485
}
484486
}
485487

488+
// This is a replacement for bincode::serialize_into(&vec)
489+
// The default implementation Write for Vec will basically
490+
// call extend_from_slice(). Serde ends up calling that for ever
491+
// field of a struct that we're serializing. extend_from_slice()
492+
// does not get inlined and thus we end up calling a generic memcpy()
493+
// implementation. If we instead reserve enough room for the serialized
494+
// struct in the Vec ahead of time we can rely on that and use
495+
// the following UnsafeVecWriter to write into the vec without
496+
// any checks.
497+
struct UnsafeVecWriter<'a>(&'a mut Vec<u8>);
498+
499+
impl<'a> Write for UnsafeVecWriter<'a> {
500+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
501+
unsafe {
502+
let old_len = self.0.len();
503+
self.0.set_len(old_len + buf.len());
504+
ptr::copy_nonoverlapping(buf.as_ptr(), self.0.as_mut_ptr().offset(old_len as isize), buf.len());
505+
}
506+
Ok(buf.len())
507+
}
508+
fn flush(&mut self) -> io::Result<()> { Ok(()) }
509+
}
510+
511+
struct SizeCounter(usize);
512+
513+
impl<'a> Write for SizeCounter {
514+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
515+
self.0 += buf.len();
516+
Ok(buf.len())
517+
}
518+
fn flush(&mut self) -> io::Result<()> { Ok(()) }
519+
}
520+
521+
fn serialize_fast<T: Serialize>(vec: &mut Vec<u8>, e: &T) {
522+
// manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason
523+
let mut size = SizeCounter(0);
524+
bincode::serialize_into(&mut size,e , bincode::Infinite).unwrap();
525+
vec.reserve(size.0);
526+
527+
bincode::serialize_into(&mut UnsafeVecWriter(vec), e, bincode::Infinite).unwrap();
528+
}
529+
486530
#[derive(Clone)]
487531
pub struct DisplayListBuilder {
488532
pub data: Vec<u8>,
@@ -541,28 +585,26 @@ impl DisplayListBuilder {
541585
}
542586

543587
fn push_item(&mut self, item: SpecificDisplayItem, info: &LayoutPrimitiveInfo) {
544-
bincode::serialize_into(
588+
serialize_fast(
545589
&mut self.data,
546590
&DisplayItem {
547591
item,
548592
clip_and_scroll: *self.clip_stack.last().unwrap(),
549593
info: *info,
550594
},
551-
bincode::Infinite,
552-
).unwrap();
595+
)
553596
}
554597

555598
fn push_new_empty_item(&mut self, item: SpecificDisplayItem) {
556599
let info = LayoutPrimitiveInfo::new(LayoutRect::zero());
557-
bincode::serialize_into(
600+
serialize_fast(
558601
&mut self.data,
559602
&DisplayItem {
560603
item,
561604
clip_and_scroll: *self.clip_stack.last().unwrap(),
562605
info,
563-
},
564-
bincode::Infinite,
565-
).unwrap();
606+
}
607+
)
566608
}
567609

568610
fn push_iter<I>(&mut self, iter: I)
@@ -575,10 +617,10 @@ impl DisplayListBuilder {
575617
let len = iter.len();
576618
let mut count = 0;
577619

578-
bincode::serialize_into(&mut self.data, &len, bincode::Infinite).unwrap();
620+
serialize_fast(&mut self.data, &len);
579621
for elem in iter {
580622
count += 1;
581-
bincode::serialize_into(&mut self.data, &elem, bincode::Infinite).unwrap();
623+
serialize_fast(&mut self.data, &elem);
582624
}
583625

584626
debug_assert_eq!(len, count);
@@ -1103,8 +1145,8 @@ impl DisplayListBuilder {
11031145

11041146
// Append glyph data to the end
11051147
for ((font_key, color), sub_glyphs) in glyphs {
1106-
bincode::serialize_into(&mut self.data, &font_key, bincode::Infinite).unwrap();
1107-
bincode::serialize_into(&mut self.data, &color, bincode::Infinite).unwrap();
1148+
serialize_fast(&mut self.data, &font_key);
1149+
serialize_fast(&mut self.data, &color);
11081150
self.push_iter(sub_glyphs);
11091151
}
11101152

0 commit comments

Comments
 (0)