From a626bdab774b5e9e9845138fca79cb099c700afe Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Fri, 29 May 2020 14:25:43 +0200 Subject: [PATCH] kernel/vm: Remove linear search from _get_next_area_info. This introduces VMAddressSpace::FindClosestArea() that can be used to find the closest area to a given address in either direction. This is now trivial and efficient since both kernel and user address spaces use a binary search tree. Using FindClosestArea() getting multiple area infos is sped up dramatically as it removes the need for a linear search from the first area to the one given in the cookie on each successive invocation. Change-Id: I227da87d915f6f3d3ef88bfeb6be5d4c97c3baaa Reviewed-on: https://review.haiku-os.org/c/haiku/+/2840 Reviewed-by: waddlesplash --- headers/private/kernel/vm/VMAddressSpace.h | 2 ++ src/system/kernel/vm/VMKernelAddressSpace.cpp | 12 ++++++++++++ src/system/kernel/vm/VMKernelAddressSpace.h | 2 ++ src/system/kernel/vm/VMUserAddressSpace.cpp | 11 +++++++++++ src/system/kernel/vm/VMUserAddressSpace.h | 2 ++ src/system/kernel/vm/vm.cpp | 11 ++--------- 6 files changed, 31 insertions(+), 9 deletions(-) diff --git a/headers/private/kernel/vm/VMAddressSpace.h b/headers/private/kernel/vm/VMAddressSpace.h index aa8e4ee875..1c226a4ae1 100644 --- a/headers/private/kernel/vm/VMAddressSpace.h +++ b/headers/private/kernel/vm/VMAddressSpace.h @@ -76,6 +76,8 @@ public: virtual VMArea* NextArea(VMArea* area) const = 0; virtual VMArea* LookupArea(addr_t address) const = 0; + virtual VMArea* FindClosestArea(addr_t address, bool less) const + = 0; virtual VMArea* CreateArea(const char* name, uint32 wiring, uint32 protection, uint32 allocationFlags) = 0; diff --git a/src/system/kernel/vm/VMKernelAddressSpace.cpp b/src/system/kernel/vm/VMKernelAddressSpace.cpp index 9c22638548..5db4eb055a 100644 --- a/src/system/kernel/vm/VMKernelAddressSpace.cpp +++ b/src/system/kernel/vm/VMKernelAddressSpace.cpp @@ -171,6 +171,18 @@ VMKernelAddressSpace::LookupArea(addr_t address) const } +//! You must hold the address space's read lock. +VMArea* +VMKernelAddressSpace::FindClosestArea(addr_t address, bool less) const +{ + Range* range = fRangeTree.FindClosest(address, less); + while (range != NULL && range->type != Range::RANGE_AREA) + range = fRangeTree.Next(range); + + return range != NULL ? range->area : NULL; +} + + /*! This inserts the area you pass into the address space. It will also set the "_address" argument to its base address when the call succeeds. diff --git a/src/system/kernel/vm/VMKernelAddressSpace.h b/src/system/kernel/vm/VMKernelAddressSpace.h index c8eecb7602..489c0173ef 100644 --- a/src/system/kernel/vm/VMKernelAddressSpace.h +++ b/src/system/kernel/vm/VMKernelAddressSpace.h @@ -26,6 +26,8 @@ public: virtual VMArea* NextArea(VMArea* area) const; virtual VMArea* LookupArea(addr_t address) const; + virtual VMArea* FindClosestArea(addr_t address, bool less) + const; virtual VMArea* CreateArea(const char* name, uint32 wiring, uint32 protection, uint32 allocationFlags); virtual void DeleteArea(VMArea* area, diff --git a/src/system/kernel/vm/VMUserAddressSpace.cpp b/src/system/kernel/vm/VMUserAddressSpace.cpp index 86bdd5bd5e..90ff7f226a 100644 --- a/src/system/kernel/vm/VMUserAddressSpace.cpp +++ b/src/system/kernel/vm/VMUserAddressSpace.cpp @@ -142,6 +142,17 @@ VMUserAddressSpace::LookupArea(addr_t address) const } +//! You must hold the address space's read lock. +VMArea* +VMUserAddressSpace::FindClosestArea(addr_t address, bool less) const +{ + VMUserArea* area = fAreas.FindClosest(address, less); + while (area != NULL && area->id == RESERVED_AREA_ID) + area = fAreas.Next(area); + return area; +} + + /*! This inserts the area you pass into the address space. It will also set the "_address" argument to its base address when the call succeeds. diff --git a/src/system/kernel/vm/VMUserAddressSpace.h b/src/system/kernel/vm/VMUserAddressSpace.h index 1ae6e45b91..814b1ee699 100644 --- a/src/system/kernel/vm/VMUserAddressSpace.h +++ b/src/system/kernel/vm/VMUserAddressSpace.h @@ -21,6 +21,8 @@ public: virtual VMArea* NextArea(VMArea* area) const; virtual VMArea* LookupArea(addr_t address) const; + virtual VMArea* FindClosestArea(addr_t address, bool less) + const; virtual VMArea* CreateArea(const char* name, uint32 wiring, uint32 protection, uint32 allocationFlags); virtual void DeleteArea(VMArea* area, diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 850d8c09a8..a672595608 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -6050,21 +6050,14 @@ _get_next_area_info(team_id team, ssize_t* cookie, area_info* info, size_t size) if (!locker.IsLocked()) return B_BAD_TEAM_ID; - VMArea* area; - for (VMAddressSpace::AreaIterator it - = locker.AddressSpace()->GetAreaIterator(); - (area = it.Next()) != NULL;) { - if (area->Base() > nextBase) - break; - } - + VMArea* area = locker.AddressSpace()->FindClosestArea(nextBase, false); if (area == NULL) { nextBase = (addr_t)-1; return B_ENTRY_NOT_FOUND; } fill_area_info(area, info, size); - *cookie = (ssize_t)(area->Base()); + *cookie = (ssize_t)(area->Base() + 1); return B_OK; }