kernel/vm: Use more than one object_cache for the page mappings.

Every time a page is mapped into an area on fault, we have to
allocate a mapping object for it. While the object_cache
does have per-CPU depots, these depots only store a limited
number of items, and once they run out the object_cache's lock
must be acquired.

So, to reduce lock contention on SMP systems, create a number
of object caches corresponding to the nearest power of 2
that is equal or smaller than the count of CPUs. (We already
allocate dozens of object caches for the block allocator
no matter how many CPUs there are, so a few more depending
on CPU count shouldn't impact memory use too much. Besides,
the object_caches are wired into the low_resource system.)

This significantly reduces lock contention on SMP systems.
Same benchmark setup as yesterday (compile mime_db and relink
HaikuDepot, VMware, -j4), before:
real    0m16.981s
user    0m14.357s
sys     0m6.060s

after:
real    0m14.522s
user    0m14.194s
sys     0m4.337s

And the page_mappings object_cache locks went from having 200,000+ waits
and ~14 seconds waiting time (across all threads) down to ~900 (yes,
that's not a typo) and ~0.05s wait time (though these numbers were captured
in conjunction with the following commit.)
This commit is contained in:
Augustin Cavalier
2024-07-24 16:31:20 -04:00
parent f44ebcb614
commit 08c53ca964
11 changed files with 81 additions and 34 deletions
+2 -4
View File
@@ -17,7 +17,6 @@
struct generic_io_vec;
struct kernel_args;
struct ObjectCache;
struct system_memory_info;
struct VMAddressSpace;
struct VMArea;
@@ -48,9 +47,6 @@ struct VMPageWiringInfo;
#define VM_MEMORY_RESERVE_SYSTEM (VM_PAGE_RESERVE_SYSTEM * B_PAGE_SIZE)
extern struct ObjectCache* gPageMappingsObjectCache;
#ifdef __cplusplus
extern "C" {
#endif
@@ -86,6 +82,8 @@ area_id transfer_area(area_id id, void** _address, uint32 addressSpec,
const char* vm_cache_type_to_string(int32 type);
void vm_free_page_mapping(page_num_t page, vm_page_mapping* mapping, uint32 flags);
status_t vm_prepare_kernel_area_debug_protection(area_id id, void** cookie);
status_t vm_set_kernel_area_debug_protection(void* cookie, void* _address,
size_t size, uint32 protection);