forked from mirrors/jj
index: optimize heads_pos() to cache generation numbers during computation
Apparently, IndexEntry::generation_number() isn't cheap probably because it involves random access to larger memory region, and the u32 value might not be aligned. Let's instead store the generation numbers in BinaryHeap. Also, heads_pos() becomes slightly faster by keeping the BinaryHeap entries small, so I've removed the IndexEntry at all. This makes the default log and disambiguation revsets fast, which evaluate 'heads(immutable_heads())'. "bench revset" result in my linux repo: revsets/heads(tags()) --------------------- baseline 3.28 560.6±4.01ms 1 2.92 500.0±2.99ms 2 (this) 1.98 339.6±1.64ms
This commit is contained in:
parent
1e933b84dd
commit
9832ee205d
1 changed files with 33 additions and 5 deletions
|
@ -967,7 +967,7 @@ impl<'a> CompositeIndex<'a> {
|
|||
let entry = self.entry_by_pos(*pos);
|
||||
min_generation = min(min_generation, entry.generation_number());
|
||||
for parent_entry in entry.parents() {
|
||||
work.push(IndexEntryByGeneration(parent_entry));
|
||||
work.push(IndexPositionByGeneration::from(&parent_entry));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -975,16 +975,17 @@ impl<'a> CompositeIndex<'a> {
|
|||
// set of candidates. Stop walking when we have gone past the minimum
|
||||
// candidate generation.
|
||||
let mut visited = HashSet::new();
|
||||
while let Some(IndexEntryByGeneration(item)) = work.pop() {
|
||||
while let Some(item) = work.pop() {
|
||||
if !visited.insert(item.pos) {
|
||||
continue;
|
||||
}
|
||||
if item.generation_number() < min_generation {
|
||||
if item.generation < min_generation {
|
||||
break;
|
||||
}
|
||||
candidate_positions.remove(&item.pos);
|
||||
for parent_entry in item.parents() {
|
||||
work.push(IndexEntryByGeneration(parent_entry));
|
||||
let entry = self.entry_by_pos(item.pos);
|
||||
for parent_entry in entry.parents() {
|
||||
work.push(IndexPositionByGeneration::from(&parent_entry));
|
||||
}
|
||||
}
|
||||
candidate_positions
|
||||
|
@ -1126,6 +1127,33 @@ impl PartialOrd for IndexEntryByGeneration<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Wrapper to sort `IndexPosition` by its generation number.
|
||||
///
|
||||
/// This is similar to `IndexEntry` newtypes, but optimized for size and cache
|
||||
/// locality. The original `IndexEntry` will have to be looked up when needed.
|
||||
#[derive(Clone, Copy, Debug, Ord, PartialOrd)]
|
||||
struct IndexPositionByGeneration {
|
||||
generation: u32, // order by generation number
|
||||
pos: IndexPosition, // tie breaker
|
||||
}
|
||||
|
||||
impl Eq for IndexPositionByGeneration {}
|
||||
|
||||
impl PartialEq for IndexPositionByGeneration {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.pos == other.pos
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&IndexEntry<'_>> for IndexPositionByGeneration {
|
||||
fn from(entry: &IndexEntry<'_>) -> Self {
|
||||
IndexPositionByGeneration {
|
||||
generation: entry.generation_number(),
|
||||
pos: entry.position(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait RevWalkIndex<'a> {
|
||||
type Entry: Clone + Ord + RevWalkIndexEntry<'a>;
|
||||
|
||||
|
|
Loading…
Reference in a new issue