Skip to content

Commit

Permalink
remove seek from std::io::MemWriter, add SeekableMemWriter to librustc
Browse files Browse the repository at this point in the history
Not all users of MemWriter need to seek, but having MemWriter
seekable adds between 3-29% in overhead in certain circumstances.
This fixes that performance gap by making a non-seekable MemWriter,
and creating a new SeekableMemWriter for those circumstances when
that functionality is actually needed.

```
test io::mem::test::bench_buf_reader                        ... bench:       682 ns/iter (+/- 85)
test io::mem::test::bench_buf_writer                        ... bench:       580 ns/iter (+/- 57)
test io::mem::test::bench_mem_reader                        ... bench:       793 ns/iter (+/- 99)
test io::mem::test::bench_mem_writer_001_0000               ... bench:        48 ns/iter (+/- 27)
test io::mem::test::bench_mem_writer_001_0010               ... bench:        65 ns/iter (+/- 27) = 153 MB/s
test io::mem::test::bench_mem_writer_001_0100               ... bench:       132 ns/iter (+/- 12) = 757 MB/s
test io::mem::test::bench_mem_writer_001_1000               ... bench:       802 ns/iter (+/- 151) = 1246 MB/s
test io::mem::test::bench_mem_writer_100_0000               ... bench:       481 ns/iter (+/- 28)
test io::mem::test::bench_mem_writer_100_0010               ... bench:      1957 ns/iter (+/- 126) = 510 MB/s
test io::mem::test::bench_mem_writer_100_0100               ... bench:      8222 ns/iter (+/- 434) = 1216 MB/s
test io::mem::test::bench_mem_writer_100_1000               ... bench:     82496 ns/iter (+/- 11191) = 1212 MB/s
test io::mem::test::bench_seekable_mem_writer_001_0000      ... bench:        48 ns/iter (+/- 2)
test io::mem::test::bench_seekable_mem_writer_001_0010      ... bench:        64 ns/iter (+/- 2) = 156 MB/s
test io::mem::test::bench_seekable_mem_writer_001_0100      ... bench:       129 ns/iter (+/- 7) = 775 MB/s
test io::mem::test::bench_seekable_mem_writer_001_1000      ... bench:       801 ns/iter (+/- 159) = 1248 MB/s
test io::mem::test::bench_seekable_mem_writer_100_0000      ... bench:       711 ns/iter (+/- 51)
test io::mem::test::bench_seekable_mem_writer_100_0010      ... bench:      2532 ns/iter (+/- 227) = 394 MB/s
test io::mem::test::bench_seekable_mem_writer_100_0100      ... bench:      8962 ns/iter (+/- 947) = 1115 MB/s
test io::mem::test::bench_seekable_mem_writer_100_1000      ... bench:     85086 ns/iter (+/- 11555) = 1175 MB/s
```

[breaking-change]
  • Loading branch information
erickt committed Jul 29, 2014
1 parent ce2824d commit e27b88d
Show file tree
Hide file tree
Showing 12 changed files with 528 additions and 143 deletions.
4 changes: 4 additions & 0 deletions src/librustc/lib.rs
Expand Up @@ -48,6 +48,9 @@ extern crate time;
#[phase(plugin, link)] extern crate log;
#[phase(plugin, link)] extern crate syntax;

#[cfg(test)]
extern crate test;

mod diagnostics;

pub mod back {
Expand Down Expand Up @@ -129,6 +132,7 @@ pub mod util {

pub mod common;
pub mod ppaux;
pub mod io;
pub mod nodemap;
}

Expand Down
24 changes: 12 additions & 12 deletions src/librustc/metadata/encoder.rs
Expand Up @@ -26,14 +26,14 @@ use middle::ty;
use middle::typeck;
use middle::stability;
use middle;
use util::io::SeekableMemWriter;
use util::nodemap::{NodeMap, NodeSet};

use serialize::Encodable;
use std::cell::RefCell;
use std::gc::Gc;
use std::hash::Hash;
use std::hash;
use std::io::MemWriter;
use std::mem;
use std::collections::HashMap;
use syntax::abi;
Expand Down Expand Up @@ -61,7 +61,7 @@ pub enum InlinedItemRef<'a> {
IIForeignRef(&'a ast::ForeignItem)
}

pub type Encoder<'a> = writer::Encoder<'a, MemWriter>;
pub type Encoder<'a> = writer::Encoder<'a, SeekableMemWriter>;

pub type EncodeInlinedItem<'a> = |ecx: &EncodeContext,
ebml_w: &mut Encoder,
Expand Down Expand Up @@ -1407,7 +1407,7 @@ fn encode_info_for_items(ecx: &EncodeContext,
// Path and definition ID indexing

fn encode_index<T: Hash>(ebml_w: &mut Encoder, index: Vec<entry<T>>,
write_fn: |&mut MemWriter, &T|) {
write_fn: |&mut SeekableMemWriter, &T|) {
let mut buckets: Vec<Vec<entry<T>>> = Vec::from_fn(256, |_| Vec::new());
for elt in index.move_iter() {
let h = hash::hash(&elt.val) as uint;
Expand All @@ -1424,7 +1424,7 @@ fn encode_index<T: Hash>(ebml_w: &mut Encoder, index: Vec<entry<T>>,
ebml_w.start_tag(tag_index_buckets_bucket_elt);
assert!(elt.pos < 0xffff_ffff);
{
let wr: &mut MemWriter = ebml_w.writer;
let wr: &mut SeekableMemWriter = ebml_w.writer;
wr.write_be_u32(elt.pos as u32);
}
write_fn(ebml_w.writer, &elt.val);
Expand All @@ -1436,15 +1436,15 @@ fn encode_index<T: Hash>(ebml_w: &mut Encoder, index: Vec<entry<T>>,
ebml_w.start_tag(tag_index_table);
for pos in bucket_locs.iter() {
assert!(*pos < 0xffff_ffff);
let wr: &mut MemWriter = ebml_w.writer;
let wr: &mut SeekableMemWriter = ebml_w.writer;
wr.write_be_u32(*pos as u32);
}
ebml_w.end_tag();
ebml_w.end_tag();
}

fn write_i64(writer: &mut MemWriter, &n: &i64) {
let wr: &mut MemWriter = writer;
fn write_i64(writer: &mut SeekableMemWriter, &n: &i64) {
let wr: &mut SeekableMemWriter = writer;
assert!(n < 0x7fff_ffff);
wr.write_be_u32(n as u32);
}
Expand Down Expand Up @@ -1545,14 +1545,14 @@ fn encode_lang_items(ecx: &EncodeContext, ebml_w: &mut Encoder) {

ebml_w.start_tag(tag_lang_items_item_id);
{
let wr: &mut MemWriter = ebml_w.writer;
let wr: &mut SeekableMemWriter = ebml_w.writer;
wr.write_be_u32(i as u32);
}
ebml_w.end_tag(); // tag_lang_items_item_id

ebml_w.start_tag(tag_lang_items_item_node_id);
{
let wr: &mut MemWriter = ebml_w.writer;
let wr: &mut SeekableMemWriter = ebml_w.writer;
wr.write_be_u32(id.node as u32);
}
ebml_w.end_tag(); // tag_lang_items_item_node_id
Expand Down Expand Up @@ -1824,12 +1824,12 @@ pub static metadata_encoding_version : &'static [u8] =
0, 0, 0, 1 ];

pub fn encode_metadata(parms: EncodeParams, krate: &Crate) -> Vec<u8> {
let mut wr = MemWriter::new();
let mut wr = SeekableMemWriter::new();
encode_metadata_inner(&mut wr, parms, krate);
wr.unwrap().move_iter().collect()
}

fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate) {
fn encode_metadata_inner(wr: &mut SeekableMemWriter, parms: EncodeParams, krate: &Crate) {
struct Stats {
attr_bytes: u64,
dep_bytes: u64,
Expand Down Expand Up @@ -1982,7 +1982,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)

// Get the encoded string for a type
pub fn encoded_ty(tcx: &ty::ctxt, t: ty::t) -> String {
let mut wr = MemWriter::new();
let mut wr = SeekableMemWriter::new();
tyencode::enc_ty(&mut wr, &tyencode::ctxt {
diag: tcx.sess.diagnostic(),
ds: def_to_string,
Expand Down
45 changes: 23 additions & 22 deletions src/librustc/metadata/tyencode.rs
Expand Up @@ -15,7 +15,6 @@

use std::cell::RefCell;
use std::collections::HashMap;
use std::io::MemWriter;

use middle::subst;
use middle::subst::VecPerParamSpace;
Expand All @@ -28,6 +27,8 @@ use syntax::ast::*;
use syntax::diagnostic::SpanHandler;
use syntax::parse::token;

use util::io::SeekableMemWriter;

macro_rules! mywrite( ($($arg:tt)*) => ({ write!($($arg)*); }) )

pub struct ctxt<'a> {
Expand All @@ -48,7 +49,7 @@ pub struct ty_abbrev {

pub type abbrev_map = RefCell<HashMap<ty::t, ty_abbrev>>;

pub fn enc_ty(w: &mut MemWriter, cx: &ctxt, t: ty::t) {
pub fn enc_ty(w: &mut SeekableMemWriter, cx: &ctxt, t: ty::t) {
match cx.abbrevs.borrow_mut().find(&t) {
Some(a) => { w.write(a.s.as_bytes()); return; }
None => {}
Expand All @@ -72,19 +73,19 @@ pub fn enc_ty(w: &mut MemWriter, cx: &ctxt, t: ty::t) {
}
}

fn enc_mutability(w: &mut MemWriter, mt: ast::Mutability) {
fn enc_mutability(w: &mut SeekableMemWriter, mt: ast::Mutability) {
match mt {
MutImmutable => (),
MutMutable => mywrite!(w, "m"),
}
}

fn enc_mt(w: &mut MemWriter, cx: &ctxt, mt: ty::mt) {
fn enc_mt(w: &mut SeekableMemWriter, cx: &ctxt, mt: ty::mt) {
enc_mutability(w, mt.mutbl);
enc_ty(w, cx, mt.ty);
}

fn enc_opt<T>(w: &mut MemWriter, t: Option<T>, enc_f: |&mut MemWriter, T|) {
fn enc_opt<T>(w: &mut SeekableMemWriter, t: Option<T>, enc_f: |&mut SeekableMemWriter, T|) {
match t {
None => mywrite!(w, "n"),
Some(v) => {
Expand All @@ -94,10 +95,10 @@ fn enc_opt<T>(w: &mut MemWriter, t: Option<T>, enc_f: |&mut MemWriter, T|) {
}
}

fn enc_vec_per_param_space<T>(w: &mut MemWriter,
fn enc_vec_per_param_space<T>(w: &mut SeekableMemWriter,
cx: &ctxt,
v: &VecPerParamSpace<T>,
op: |&mut MemWriter, &ctxt, &T|) {
op: |&mut SeekableMemWriter, &ctxt, &T|) {
for &space in subst::ParamSpace::all().iter() {
mywrite!(w, "[");
for t in v.get_slice(space).iter() {
Expand All @@ -107,13 +108,13 @@ fn enc_vec_per_param_space<T>(w: &mut MemWriter,
}
}

pub fn enc_substs(w: &mut MemWriter, cx: &ctxt, substs: &subst::Substs) {
pub fn enc_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::Substs) {
enc_region_substs(w, cx, &substs.regions);
enc_vec_per_param_space(w, cx, &substs.types,
|w, cx, &ty| enc_ty(w, cx, ty));
}

fn enc_region_substs(w: &mut MemWriter, cx: &ctxt, substs: &subst::RegionSubsts) {
fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::RegionSubsts) {
match *substs {
subst::ErasedRegions => {
mywrite!(w, "e");
Expand All @@ -126,7 +127,7 @@ fn enc_region_substs(w: &mut MemWriter, cx: &ctxt, substs: &subst::RegionSubsts)
}
}

fn enc_region(w: &mut MemWriter, cx: &ctxt, r: ty::Region) {
fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
match r {
ty::ReLateBound(id, br) => {
mywrite!(w, "b[{}|", id);
Expand Down Expand Up @@ -161,7 +162,7 @@ fn enc_region(w: &mut MemWriter, cx: &ctxt, r: ty::Region) {
}
}

fn enc_bound_region(w: &mut MemWriter, cx: &ctxt, br: ty::BoundRegion) {
fn enc_bound_region(w: &mut SeekableMemWriter, cx: &ctxt, br: ty::BoundRegion) {
match br {
ty::BrAnon(idx) => {
mywrite!(w, "a{}|", idx);
Expand All @@ -177,12 +178,12 @@ fn enc_bound_region(w: &mut MemWriter, cx: &ctxt, br: ty::BoundRegion) {
}
}

pub fn enc_trait_ref(w: &mut MemWriter, cx: &ctxt, s: &ty::TraitRef) {
pub fn enc_trait_ref(w: &mut SeekableMemWriter, cx: &ctxt, s: &ty::TraitRef) {
mywrite!(w, "{}|", (cx.ds)(s.def_id));
enc_substs(w, cx, &s.substs);
}

pub fn enc_trait_store(w: &mut MemWriter, cx: &ctxt, s: ty::TraitStore) {
pub fn enc_trait_store(w: &mut SeekableMemWriter, cx: &ctxt, s: ty::TraitStore) {
match s {
ty::UniqTraitStore => mywrite!(w, "~"),
ty::RegionTraitStore(re, m) => {
Expand All @@ -193,7 +194,7 @@ pub fn enc_trait_store(w: &mut MemWriter, cx: &ctxt, s: ty::TraitStore) {
}
}

fn enc_sty(w: &mut MemWriter, cx: &ctxt, st: &ty::sty) {
fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
match *st {
ty::ty_nil => mywrite!(w, "n"),
ty::ty_bot => mywrite!(w, "z"),
Expand Down Expand Up @@ -293,33 +294,33 @@ fn enc_sty(w: &mut MemWriter, cx: &ctxt, st: &ty::sty) {
}
}

fn enc_fn_style(w: &mut MemWriter, p: FnStyle) {
fn enc_fn_style(w: &mut SeekableMemWriter, p: FnStyle) {
match p {
NormalFn => mywrite!(w, "n"),
UnsafeFn => mywrite!(w, "u"),
}
}

fn enc_abi(w: &mut MemWriter, abi: Abi) {
fn enc_abi(w: &mut SeekableMemWriter, abi: Abi) {
mywrite!(w, "[");
mywrite!(w, "{}", abi.name());
mywrite!(w, "]")
}

fn enc_onceness(w: &mut MemWriter, o: Onceness) {
fn enc_onceness(w: &mut SeekableMemWriter, o: Onceness) {
match o {
Once => mywrite!(w, "o"),
Many => mywrite!(w, "m")
}
}

pub fn enc_bare_fn_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::BareFnTy) {
pub fn enc_bare_fn_ty(w: &mut SeekableMemWriter, cx: &ctxt, ft: &ty::BareFnTy) {
enc_fn_style(w, ft.fn_style);
enc_abi(w, ft.abi);
enc_fn_sig(w, cx, &ft.sig);
}

pub fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) {
pub fn enc_closure_ty(w: &mut SeekableMemWriter, cx: &ctxt, ft: &ty::ClosureTy) {
enc_fn_style(w, ft.fn_style);
enc_onceness(w, ft.onceness);
enc_trait_store(w, cx, ft.store);
Expand All @@ -330,7 +331,7 @@ pub fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) {
enc_abi(w, ft.abi);
}

fn enc_fn_sig(w: &mut MemWriter, cx: &ctxt, fsig: &ty::FnSig) {
fn enc_fn_sig(w: &mut SeekableMemWriter, cx: &ctxt, fsig: &ty::FnSig) {
mywrite!(w, "[{}|", fsig.binder_id);
for ty in fsig.inputs.iter() {
enc_ty(w, cx, *ty);
Expand All @@ -344,7 +345,7 @@ fn enc_fn_sig(w: &mut MemWriter, cx: &ctxt, fsig: &ty::FnSig) {
enc_ty(w, cx, fsig.output);
}

fn enc_bounds(w: &mut MemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
for bound in bs.builtin_bounds.iter() {
match bound {
ty::BoundSend => mywrite!(w, "S"),
Expand All @@ -363,7 +364,7 @@ fn enc_bounds(w: &mut MemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
mywrite!(w, ".");
}

pub fn enc_type_param_def(w: &mut MemWriter, cx: &ctxt, v: &ty::TypeParameterDef) {
pub fn enc_type_param_def(w: &mut SeekableMemWriter, cx: &ctxt, v: &ty::TypeParameterDef) {
mywrite!(w, "{}:{}|{}|{}|",
token::get_ident(v.ident), (cx.ds)(v.def_id),
v.space.to_uint(), v.index);
Expand Down
8 changes: 3 additions & 5 deletions src/librustc/middle/astencode.rs
Expand Up @@ -28,6 +28,7 @@ use middle::subst;
use middle::subst::VecPerParamSpace;
use middle::typeck::{MethodCall, MethodCallee, MethodOrigin};
use middle::{ty, typeck};
use util::io::SeekableMemWriter;
use util::ppaux::ty_to_string;

use syntax::{ast, ast_map, ast_util, codemap, fold};
Expand All @@ -39,7 +40,6 @@ use syntax;

use libc;
use std::io::Seek;
use std::io::MemWriter;
use std::mem;
use std::gc::GC;

Expand Down Expand Up @@ -73,7 +73,7 @@ trait tr_intern {
fn tr_intern(&self, xcx: &ExtendedDecodeContext) -> ast::DefId;
}

pub type Encoder<'a> = writer::Encoder<'a, MemWriter>;
pub type Encoder<'a> = writer::Encoder<'a, SeekableMemWriter>;

// ______________________________________________________________________
// Top-level methods.
Expand Down Expand Up @@ -1573,10 +1573,8 @@ fn mk_ctxt() -> parse::ParseSess {

#[cfg(test)]
fn roundtrip(in_item: Option<Gc<ast::Item>>) {
use std::io::MemWriter;

let in_item = in_item.unwrap();
let mut wr = MemWriter::new();
let mut wr = SeekableMemWriter::new();
{
let mut ebml_w = writer::Encoder::new(&mut wr);
encode_item_ast(&mut ebml_w, in_item);
Expand Down

0 comments on commit e27b88d

Please sign in to comment.