Minor speedup tuning for SecondaryMap (#1020)
The `SecondaryMap` abstraction -- basically, resize-on-demand arrays with a default value -- is very hot in Cranelift. This small patch is the result of many profiling runs. It makes two changes: * `fn index_mut` is changed to be `#[inline(always)]`, based on profile data. * `fn index` and `fn index_mut` call `self.elems.resize()` directly, rather than via `self.resize()`. The point of this is not to improve performance. Rather, it ensures that the public functions for `SecondaryMap` do not call each other. When public interface functions call each other, it becomes difficult to interpret profiling results, because it's harder to see what fraction of costs for `SecondaryMap` as a whole come from outside the module, and what fraction is the result of "internal" calls to the external interface. The overall result, for wasm_lua_binarytrees, is a 1.4% reduction in instruction count for the compiler, and a 2.2% reduction in loads/stores.
This commit is contained in:
@@ -83,16 +83,19 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the element at `k` if it exists.
|
/// Get the element at `k` if it exists.
|
||||||
|
#[inline(always)]
|
||||||
pub fn get(&self, k: K) -> Option<&V> {
|
pub fn get(&self, k: K) -> Option<&V> {
|
||||||
self.elems.get(k.index())
|
self.elems.get(k.index())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this map completely empty?
|
/// Is this map completely empty?
|
||||||
|
#[inline(always)]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.elems.is_empty()
|
self.elems.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove all entries from this map.
|
/// Remove all entries from this map.
|
||||||
|
#[inline(always)]
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.elems.clear()
|
self.elems.clear()
|
||||||
}
|
}
|
||||||
@@ -123,7 +126,6 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Resize the map to have `n` entries by adding default entries as needed.
|
/// Resize the map to have `n` entries by adding default entries as needed.
|
||||||
#[inline]
|
|
||||||
pub fn resize(&mut self, n: usize) {
|
pub fn resize(&mut self, n: usize) {
|
||||||
self.elems.resize(n, self.default.clone());
|
self.elems.resize(n, self.default.clone());
|
||||||
}
|
}
|
||||||
@@ -139,8 +141,9 @@ where
|
|||||||
{
|
{
|
||||||
type Output = V;
|
type Output = V;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn index(&self, k: K) -> &V {
|
fn index(&self, k: K) -> &V {
|
||||||
self.get(k).unwrap_or(&self.default)
|
self.elems.get(k.index()).unwrap_or(&self.default)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,11 +155,11 @@ where
|
|||||||
K: EntityRef,
|
K: EntityRef,
|
||||||
V: Clone,
|
V: Clone,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn index_mut(&mut self, k: K) -> &mut V {
|
fn index_mut(&mut self, k: K) -> &mut V {
|
||||||
let i = k.index();
|
let i = k.index();
|
||||||
if i >= self.elems.len() {
|
if i >= self.elems.len() {
|
||||||
self.resize(i + 1);
|
self.elems.resize(i + 1, self.default.clone());
|
||||||
}
|
}
|
||||||
&mut self.elems[i]
|
&mut self.elems[i]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user