Improve buffering performance

This commit is contained in:
Kogia-sima 2020-06-18 16:32:07 +09:00
parent 48eb36560a
commit 9a7f62e3ca
6 changed files with 61 additions and 13 deletions

7
Cargo.lock generated
View File

@ -1043,6 +1043,7 @@ name = "sailfish"
version = "0.1.0"
dependencies = [
"ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1347,6 +1348,11 @@ dependencies = [
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "version_check"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
@ -1561,6 +1567,7 @@ dependencies = [
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"

View File

@ -14,3 +14,6 @@ edition = "2018"
[dependencies]
ryu = "1.0.4"
[build-dependencies]
version_check = "0.9.2"

5
sailfish/build.rs Normal file
View File

@ -0,0 +1,5 @@
fn main() {
if version_check::is_feature_flaggable() == Some(true) {
println!("cargo:rustc-cfg=sailfish_nightly");
}
}

View File

@ -34,6 +34,7 @@
#![doc(
html_logo_url = "https://raw.githubusercontent.com/Kogia-sima/sailfish/master/resources/icon.png"
)]
#![cfg_attr(sailfish_nightly, feature(core_intrinsics))]
pub mod runtime;

View File

@ -4,6 +4,20 @@ use std::mem::{align_of, ManuallyDrop};
use std::ops::{Add, AddAssign};
use std::ptr;
#[cfg(sailfish_nightly)]
macro_rules! unlikely {
($val:expr) => {
std::intrinsics::unlikely($val)
};
}
#[cfg(not(sailfish_nightly))]
macro_rules! unlikely {
($val:expr) => {
$val
};
}
/// Buffer for rendered contents
///
/// This struct is quite simular to `String`, but some methods are
@ -86,7 +100,7 @@ impl Buffer {
#[inline]
pub fn reserve(&mut self, size: usize) {
if size > self.capacity - self.len {
if unlikely!(self.len + size > self.capacity) {
self.reserve_internal(size);
}
}
@ -105,9 +119,7 @@ impl Buffer {
#[inline]
pub fn push_str(&mut self, data: &str) {
let size = data.len();
if size > self.capacity - self.len {
self.reserve_internal(size);
}
self.reserve(size);
unsafe {
let p = self.data.add(self.len);
std::ptr::copy_nonoverlapping(data.as_ptr(), p, size);
@ -121,28 +133,31 @@ impl Buffer {
self.push_str(data.encode_utf8(&mut buf));
}
#[inline(never)]
#[inline]
fn reserve_internal(&mut self, size: usize) {
unsafe {
let new_capacity = std::cmp::max(self.capacity * 2, self.len + size);
self.realloc(new_capacity);
self.data = self.realloc(new_capacity);
self.capacity = new_capacity;
}
}
unsafe fn realloc(&mut self, cap: usize) {
if self.capacity == 0 {
#[inline]
unsafe fn realloc(&self, cap: usize) -> *mut u8 {
let data = if unlikely!(self.capacity == 0) {
let new_layout = Layout::from_size_align_unchecked(cap, 1);
self.data = alloc(new_layout);
alloc(new_layout)
} else {
assert!(cap <= std::usize::MAX / 2, "capacity is too large");
debug_assert!(cap <= std::usize::MAX / 2, "capacity is too large");
let old_layout = Layout::from_size_align_unchecked(self.capacity, 1);
self.data = realloc(self.data, old_layout, cap);
}
realloc(self.data, old_layout, cap)
};
if self.data.is_null() {
if data.is_null() {
handle_alloc_error(Layout::from_size_align_unchecked(cap, 1));
}
data
}
}

View File

@ -55,3 +55,20 @@ impl Context {
Ok(self.buf.into_string())
}
}
// #[inline(never)]
// pub fn _instantiate(table: Vec<Vec<usize>>) -> String {
// let mut buffer = Buffer::with_capacity(130000);
// buffer.push_str("<table>");
// for r1 in table {
// buffer.push_str("<tr><td>");
// for r2 in r1 {
// let _ = (&r2).render(&mut buffer);
// buffer.push_str("</td><td>");
// }
// unsafe { buffer.set_len(buffer.len() - 4) }
// buffer.push_str("</tr>");
// }
// buffer.push_str("</table>");
// buffer.into_string()
// }