peepmatic: Represent various id types with u16

These ids end up in the automaton, so making them smaller should give us better
data cache locality and also smaller serialized sizes.
This commit is contained in:
Nick Fitzgerald
2020-05-07 13:56:02 -07:00
parent 469104c4d3
commit 210b036320
7 changed files with 27 additions and 27 deletions

View File

@@ -7,11 +7,11 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::num::NonZeroU32; use std::num::{NonZeroU16, NonZeroU32};
/// An identifier for an interned integer. /// An identifier for an interned integer.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct IntegerId(#[doc(hidden)] pub NonZeroU32); pub struct IntegerId(#[doc(hidden)] pub NonZeroU16);
/// An interner for integer values. /// An interner for integer values.
#[derive(Debug, Default, Serialize, Deserialize)] #[derive(Debug, Default, Serialize, Deserialize)]
@@ -40,8 +40,8 @@ impl IntegerInterner {
return *id; return *id;
} }
assert!((self.values.len() as u64) < (std::u32::MAX as u64)); assert!((self.values.len() as u64) < (std::u16::MAX as u64));
let id = IntegerId(unsafe { NonZeroU32::new_unchecked(self.values.len() as u32 + 1) }); let id = IntegerId(unsafe { NonZeroU16::new_unchecked(self.values.len() as u16 + 1) });
self.values.push(value); self.values.push(value);
self.map.insert(value, id); self.map.insert(value, id);
@@ -65,16 +65,9 @@ impl IntegerInterner {
} }
} }
impl From<IntegerId> for u32 {
#[inline]
fn from(id: IntegerId) -> u32 {
id.0.get()
}
}
impl From<IntegerId> for NonZeroU32 { impl From<IntegerId> for NonZeroU32 {
#[inline] #[inline]
fn from(id: IntegerId) -> NonZeroU32 { fn from(id: IntegerId) -> NonZeroU32 {
id.0 id.0.into()
} }
} }

View File

@@ -149,11 +149,11 @@ pub enum MatchOp {
/// A canonicalized identifier for a left-hand side value that was bound in a /// A canonicalized identifier for a left-hand side value that was bound in a
/// pattern. /// pattern.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct LhsId(pub u32); pub struct LhsId(pub u16);
/// A canonicalized identifier for a right-hand side value. /// A canonicalized identifier for a right-hand side value.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct RhsId(pub u32); pub struct RhsId(pub u16);
/// An action to perform when transitioning between states in the automata. /// An action to perform when transitioning between states in the automata.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
@@ -243,18 +243,22 @@ pub enum Action {
mod tests { mod tests {
use super::*; use super::*;
// These types all end up in the automaton, so we should take care that they
// are small and don't fill up the data cache (or take up too much
// serialized size).
#[test] #[test]
fn match_result_is_4_bytes_in_size() { fn match_result_size() {
assert_eq!(std::mem::size_of::<MatchResult>(), 4); assert_eq!(std::mem::size_of::<MatchResult>(), 4);
} }
#[test] #[test]
fn match_op_is_12_bytes_in_size() { fn match_op_size() {
assert_eq!(std::mem::size_of::<MatchOp>(), 12); assert_eq!(std::mem::size_of::<MatchOp>(), 6);
} }
#[test] #[test]
fn action_is_20_bytes_in_size() { fn action_size() {
assert_eq!(std::mem::size_of::<Action>(), 20); assert_eq!(std::mem::size_of::<Action>(), 16);
} }
} }

View File

@@ -414,7 +414,7 @@ where
Part::Constant(c) => { Part::Constant(c) => {
let x = c.as_int().ok_or(Else)?; let x = c.as_int().ok_or(Else)?;
let id = self.peep_opt.integers.already_interned(x).ok_or(Else)?; let id = self.peep_opt.integers.already_interned(x).ok_or(Else)?;
Ok(id.0) Ok(id.into())
} }
Part::Instruction(i) => { Part::Instruction(i) => {
let c = self let c = self
@@ -423,7 +423,7 @@ where
.ok_or(Else)?; .ok_or(Else)?;
let x = c.as_int().ok_or(Else)?; let x = c.as_int().ok_or(Else)?;
let id = self.peep_opt.integers.already_interned(x).ok_or(Else)?; let id = self.peep_opt.integers.already_interned(x).ok_or(Else)?;
Ok(id.0) Ok(id.into())
} }
Part::ConditionCode(_) => unreachable!("IntegerValue on condition code"), Part::ConditionCode(_) => unreachable!("IntegerValue on condition code"),
} }

View File

@@ -46,7 +46,7 @@ impl Path<'_> {
/// An identifier for an interned path. /// An identifier for an interned path.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct PathId(u32); pub struct PathId(u16);
/// An interner and de-duplicator for `Path`s. /// An interner and de-duplicator for `Path`s.
/// ///
@@ -93,7 +93,7 @@ impl PathInterner {
#[inline(never)] #[inline(never)]
fn intern_new<'a>(&mut self, path: Path<'a>) -> PathId { fn intern_new<'a>(&mut self, path: Path<'a>) -> PathId {
let id: u32 = self let id: u16 = self
.paths .paths
.len() .len()
.try_into() .try_into()

View File

@@ -10,9 +10,9 @@ use peepmatic_runtime::{
operator::Operator, operator::Operator,
paths::{PathId, PathInterner}, paths::{PathId, PathInterner},
}; };
use std::convert::TryFrom; use std::convert::{TryFrom, TryInto};
use std::io::{self, Write}; use std::io::{self, Write};
use std::num::NonZeroU32; use std::num::NonZeroU16;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct PeepholeDotFmt<'a>(pub(crate) &'a PathInterner, pub(crate) &'a IntegerInterner); pub(crate) struct PeepholeDotFmt<'a>(pub(crate) &'a PathInterner, pub(crate) &'a IntegerInterner);
@@ -39,7 +39,9 @@ impl DotFmt<linear::MatchResult, linear::MatchOp, Vec<linear::Action>> for Peeph
write!(w, "{}", cc) write!(w, "{}", cc)
} }
linear::MatchOp::IntegerValue { .. } => { linear::MatchOp::IntegerValue { .. } => {
let x = self.1.lookup(IntegerId(NonZeroU32::new(x).unwrap())); let x = self
.1
.lookup(IntegerId(NonZeroU16::new(x.try_into().unwrap()).unwrap()));
write!(w, "{}", x) write!(w, "{}", x)
} }
_ => write!(w, "Ok({})", x), _ => write!(w, "Ok({})", x),

View File

@@ -92,6 +92,7 @@ use peepmatic_runtime::{
paths::{Path, PathId, PathInterner}, paths::{Path, PathId, PathInterner},
}; };
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::convert::TryInto;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use wast::Id; use wast::Id;
@@ -339,7 +340,7 @@ impl<'a> RhsBuilder<'a> {
) { ) {
while let Some(rhs) = self.rhs_post_order.next() { while let Some(rhs) = self.rhs_post_order.next() {
actions.push(self.rhs_to_linear_action(integers, lhs_id_to_path, rhs)); actions.push(self.rhs_to_linear_action(integers, lhs_id_to_path, rhs));
let id = linear::RhsId(self.rhs_span_to_id.len() as u32); let id = linear::RhsId(self.rhs_span_to_id.len().try_into().unwrap());
self.rhs_span_to_id.insert(rhs.span(), id); self.rhs_span_to_id.insert(rhs.span(), id);
} }
} }