As per the IA32 specification we can save TLB invalidations in at least two

situations:
* When mapping the page the page table entry should not have been marked
  "present" before, i.e. it would not have been cached anyway.
* When the page table entry's accessed flag wasn't set, the entry hadn't been
  cached either.

Speeds up the -j8 Haiku image build only minimally, but the total kernel time
drops about 9%.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35062 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2010-01-13 22:55:52 +00:00
parent 58f1b1311f
commit 30f423606d

View File

@ -165,7 +165,7 @@ put_page_table_entry_in_pgtable(page_table_entry* entry,
page |= X86_PTE_WRITABLE; page |= X86_PTE_WRITABLE;
// put it in the page table // put it in the page table
*entry = page; *(volatile page_table_entry*)entry = page;
} }
@ -379,17 +379,15 @@ map_tmap(vm_translation_map *map, addr_t va, addr_t pa, uint32 attributes)
pd[index] & X86_PDE_ADDRESS_MASK); pd[index] & X86_PDE_ADDRESS_MASK);
index = VADDR_TO_PTENT(va); index = VADDR_TO_PTENT(va);
ASSERT((pt[index] & X86_PTE_PRESENT) == 0);
put_page_table_entry_in_pgtable(&pt[index], pa, attributes, put_page_table_entry_in_pgtable(&pt[index], pa, attributes,
IS_KERNEL_MAP(map)); IS_KERNEL_MAP(map));
pinner.Unlock(); pinner.Unlock();
if (map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE) { // Note: We don't need to invalidate the TLB for this address, as previously
map->arch_data->pages_to_invalidate[ // the entry was not present and the TLB doesn't cache those entries.
map->arch_data->num_invalidate_pages] = va;
}
map->arch_data->num_invalidate_pages++;
map->map_count++; map->map_count++;
@ -433,15 +431,22 @@ restart:
TRACE(("unmap_tmap: removing page 0x%lx\n", start)); TRACE(("unmap_tmap: removing page 0x%lx\n", start));
clear_page_table_entry_flags(&pt[index], X86_PTE_PRESENT); page_table_entry oldEntry = clear_page_table_entry_flags(&pt[index],
X86_PTE_PRESENT);
map->map_count--; map->map_count--;
if (map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE) { if ((oldEntry & X86_PTE_ACCESSED) != 0) {
map->arch_data->pages_to_invalidate[ // Note, that we only need to invalidate the address, if the
map->arch_data->num_invalidate_pages] = start; // accessed flags was set, since only then the entry could have been
} // in any TLB.
if (map->arch_data->num_invalidate_pages
< PAGE_INVALIDATE_CACHE_SIZE) {
map->arch_data->pages_to_invalidate[
map->arch_data->num_invalidate_pages] = start;
}
map->arch_data->num_invalidate_pages++; map->arch_data->num_invalidate_pages++;
}
} }
pinner.Unlock(); pinner.Unlock();
@ -585,18 +590,21 @@ restart:
} else if ((attributes & B_KERNEL_WRITE_AREA) != 0) } else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
entry |= X86_PTE_WRITABLE; entry |= X86_PTE_WRITABLE;
set_page_table_entry(&pt[index], entry); page_table_entry oldEntry = set_page_table_entry(&pt[index], entry);
// TODO: We might have cleared accessed/modified flags! // TODO: We might have cleared accessed/modified flags!
// TODO: Optimize: If the accessed flag was clear, we don't need to if ((oldEntry & X86_PTE_ACCESSED) != 0) {
// invalidate the TLB for that address. // Note, that we only need to invalidate the address, if the
// accessed flags was set, since only then the entry could have been
// in any TLB.
if (map->arch_data->num_invalidate_pages
< PAGE_INVALIDATE_CACHE_SIZE) {
map->arch_data->pages_to_invalidate[
map->arch_data->num_invalidate_pages] = start;
}
if (map->arch_data->num_invalidate_pages < PAGE_INVALIDATE_CACHE_SIZE) { map->arch_data->num_invalidate_pages++;
map->arch_data->pages_to_invalidate[
map->arch_data->num_invalidate_pages] = start;
} }
map->arch_data->num_invalidate_pages++;
} }
pinner.Unlock(); pinner.Unlock();
@ -929,12 +937,12 @@ arch_vm_translation_map_early_map(kernel_args *args, addr_t va, addr_t pa,
+ (va / B_PAGE_SIZE / 1024) * B_PAGE_SIZE), 0, B_PAGE_SIZE); + (va / B_PAGE_SIZE / 1024) * B_PAGE_SIZE), 0, B_PAGE_SIZE);
} }
ASSERT((sPageHole[va / B_PAGE_SIZE] & X86_PTE_PRESENT) == 0);
// now, fill in the pentry // now, fill in the pentry
put_page_table_entry_in_pgtable(sPageHole + va / B_PAGE_SIZE, pa, put_page_table_entry_in_pgtable(sPageHole + va / B_PAGE_SIZE, pa,
attributes, IS_KERNEL_ADDRESS(va)); attributes, IS_KERNEL_ADDRESS(va));
arch_cpu_invalidate_TLB_range(va, va);
return B_OK; return B_OK;
} }