* Renamed VMAddressSpace::ResizeArea{Head,Tail}() to ShrinkArea{Head,Tail}()

to clarify that they never enlarge the area.
* Reimplemented VMKernelAddressSpace. It is somewhat inspired by Bonwick's
  vmem resource allocator (though we have different requirements):
  - We consider the complete address space to be divided into contiguous
    ranges of type free, reserved, or area, each range being represented by
    a VMKernelAddressRange object.
  - The range objects are managed in an AVL tree and a doubly linked list
    (the latter only for faster iteration) sorted by address. This provides
    O(log(n)) lookup, insertion and removal.
  - For each power of two size we maintain a list of free ranges of at least
    that size. Thus for the most common case of B_ANY*_ADDRESS area
    allocation, we find a free range in constant time (the rest of the
    processing being O(log(n))) with a rather good fit. This should also
    help avoiding address space fragmentation.
  While the new implementation should be faster, particularly with an
  increasing number of areas, I couldn't measure any difference in the -j2
  haiku build. From a cursory test the -j8 build hasn't tangibly benefitted
  either.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34528 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-12-06 17:18:04 +00:00
parent fe30b74fde
commit 40cd019ea0
11 changed files with 874 additions and 530 deletions
+7 -3
View File
@@ -62,6 +62,8 @@ public:
VMAddressSpace*& HashTableLink() { return fHashTableLink; }
virtual status_t InitObject();
virtual VMArea* FirstArea() const = 0;
virtual VMArea* NextArea(VMArea* area) const = 0;
@@ -70,13 +72,15 @@ public:
uint32 protection) = 0;
virtual void DeleteArea(VMArea* area) = 0;
virtual status_t InsertArea(void** _address, uint32 addressSpec,
addr_t size, VMArea* area) = 0;
size_t size, VMArea* area) = 0;
virtual void RemoveArea(VMArea* area) = 0;
virtual bool CanResizeArea(VMArea* area, size_t newSize) = 0;
virtual status_t ResizeArea(VMArea* area, size_t newSize) = 0;
virtual status_t ResizeAreaHead(VMArea* area, size_t size) = 0;
virtual status_t ResizeAreaTail(VMArea* area, size_t size) = 0;
virtual status_t ShrinkAreaHead(VMArea* area, size_t newSize)
= 0;
virtual status_t ShrinkAreaTail(VMArea* area, size_t newSize)
= 0;
virtual status_t ReserveAddressRange(void** _address,
uint32 addressSpec, size_t size,
+25 -10
View File
@@ -12,6 +12,8 @@
#include <stdlib.h>
#include <new>
#include <KernelExport.h>
#include <util/OpenHashTable.h>
@@ -181,17 +183,24 @@ VMAddressSpace::RemoveAndPut()
}
status_t
VMAddressSpace::InitObject()
{
return B_OK;
}
void
VMAddressSpace::Dump() const
{
kprintf("dump of address space at %p:\n", this);
kprintf("id: 0x%lx\n", fID);
kprintf("ref_count: %ld\n", fRefCount);
kprintf("fault_count: %ld\n", fFaultCount);
kprintf("id: %" B_PRId32 "\n", fID);
kprintf("ref_count: %" B_PRId32 "\n", fRefCount);
kprintf("fault_count: %" B_PRId32 "\n", fFaultCount);
kprintf("translation_map: %p\n", &fTranslationMap);
kprintf("base: 0x%lx\n", fBase);
kprintf("end: 0x%lx\n", fEndAddress);
kprintf("change_count: 0x%lx\n", fChangeCount);
kprintf("base: %#" B_PRIxADDR "\n", fBase);
kprintf("end: %#" B_PRIxADDR "\n", fEndAddress);
kprintf("change_count: %" B_PRId32 "\n", fChangeCount);
}
@@ -205,11 +214,17 @@ VMAddressSpace::Create(team_id teamID, addr_t base, size_t size, bool kernel,
if (addressSpace == NULL)
return B_NO_MEMORY;
status_t status = addressSpace->InitObject();
if (status != B_OK) {
delete addressSpace;
return status;
}
TRACE(("vm_create_aspace: team %ld (%skernel): %#lx bytes starting at "
"%#lx => %p\n", id, kernel ? "!" : "", size, base, addressSpace));
// initialize the corresponding translation map
status_t status = arch_vm_translation_map_init_map(
status = arch_vm_translation_map_init_map(
&addressSpace->fTranslationMap, kernel);
if (status != B_OK) {
delete addressSpace;
@@ -321,9 +336,9 @@ VMAddressSpace::_DumpListCommand(int argc, char** argv)
areaSize += area->Size();
}
}
kprintf("%p %6ld %#010lx %#10lx %10ld %10lld\n",
space, space->ID(), space->Base(), space->EndAddress(), areaCount,
areaSize);
kprintf("%p %6" B_PRId32 " %#010" B_PRIxADDR " %#10" B_PRIxADDR
" %10" B_PRId32 " %10" B_PRIdOFF "\n", space, space->ID(),
space->Base(), space->EndAddress(), areaCount, areaSize);
}
return 0;
+2
View File
@@ -10,6 +10,8 @@
#include <vm/VMArea.h>
#include <new>
#include <heap.h>
File diff suppressed because it is too large Load Diff
+34 -14
View File
@@ -1,10 +1,6 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Copyright 2002-2008, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#ifndef VM_KERNEL_ADDRESS_SPACE_H
#define VM_KERNEL_ADDRESS_SPACE_H
@@ -21,6 +17,8 @@ public:
size_t size);
virtual ~VMKernelAddressSpace();
virtual status_t InitObject();
virtual VMArea* FirstArea() const;
virtual VMArea* NextArea(VMArea* area) const;
@@ -29,13 +27,13 @@ public:
uint32 protection);
virtual void DeleteArea(VMArea* area);
virtual status_t InsertArea(void** _address, uint32 addressSpec,
addr_t size, VMArea* area);
size_t size, VMArea* area);
virtual void RemoveArea(VMArea* area);
virtual bool CanResizeArea(VMArea* area, size_t newSize);
virtual status_t ResizeArea(VMArea* area, size_t newSize);
virtual status_t ResizeAreaHead(VMArea* area, size_t size);
virtual status_t ResizeAreaTail(VMArea* area, size_t size);
virtual status_t ShrinkAreaHead(VMArea* area, size_t newSize);
virtual status_t ShrinkAreaTail(VMArea* area, size_t newSize);
virtual status_t ReserveAddressRange(void** _address,
uint32 addressSpec, size_t size,
@@ -47,15 +45,37 @@ public:
virtual void Dump() const;
private:
status_t _InsertAreaIntoReservedRegion(addr_t start,
size_t size, VMKernelArea* area);
status_t _InsertAreaSlot(addr_t start, addr_t size,
addr_t end, uint32 addressSpec,
VMKernelArea* area);
typedef VMKernelAddressRange Range;
typedef VMKernelAddressRangeTree RangeTree;
typedef DoublyLinkedList<Range,
DoublyLinkedListMemberGetLink<Range, &Range::listLink> >
RangeList;
typedef DoublyLinkedList<Range, VMKernelAddressRangeGetFreeListLink>
RangeFreeList;
private:
VMKernelAreaList fAreas;
mutable VMArea* fAreaHint;
inline void _FreeListInsertRange(Range* range, size_t size);
inline void _FreeListRemoveRange(Range* range, size_t size);
void _InsertRange(Range* range);
void _RemoveRange(Range* range);
status_t _AllocateRange(addr_t address,
uint32 addressSpec, size_t size,
bool allowReservedRange, Range*& _range);
Range* _FindFreeRange(addr_t start, size_t size,
size_t alignment, uint32 addressSpec,
bool allowReservedRange,
addr_t& _foundAddress);
void _FreeRange(Range* range);
void _CheckStructures() const;
private:
RangeTree fRangeTree;
RangeList fRangeList;
RangeFreeList* fFreeLists;
int fFreeListCount;
};
-10
View File
@@ -39,13 +39,3 @@ VMKernelArea::Create(VMAddressSpace* addressSpace, const char* name,
return area;
}
/*static*/ VMKernelArea*
VMKernelArea::CreateReserved(VMAddressSpace* addressSpace, uint32 flags)
{
VMKernelArea* area = new(nogrow) VMKernelArea(addressSpace, 0, 0);
if (area != NULL)
area->id = RESERVED_AREA_ID;
return area;
}
+102 -25
View File
@@ -6,13 +6,109 @@
#define VM_KERNEL_AREA_H
#include <util/AVLTree.h>
#include <vm/VMArea.h>
struct VMKernelAddressSpace;
struct VMKernelArea;
struct VMKernelArea : VMArea {
struct VMKernelAddressRange : AVLTreeNode {
public:
// range types
enum {
RANGE_FREE,
RANGE_RESERVED,
RANGE_AREA
};
public:
DoublyLinkedListLink<VMKernelAddressRange> listLink;
addr_t base;
size_t size;
union {
VMKernelArea* area;
struct {
addr_t base;
uint32 flags;
} reserved;
DoublyLinkedListLink<VMKernelAddressRange> freeListLink;
};
int type;
public:
VMKernelAddressRange(addr_t base, size_t size, int type)
:
base(base),
size(size),
type(type)
{
}
VMKernelAddressRange(addr_t base, size_t size,
const VMKernelAddressRange* other)
:
base(base),
size(size),
type(other->type)
{
if (type == RANGE_RESERVED) {
reserved.base = other->reserved.base;
reserved.flags = other->reserved.flags;
}
}
};
struct VMKernelAddressRangeTreeDefinition {
typedef addr_t Key;
typedef VMKernelAddressRange Value;
AVLTreeNode* GetAVLTreeNode(Value* value) const
{
return value;
}
Value* GetValue(AVLTreeNode* node) const
{
return static_cast<Value*>(node);
}
int Compare(addr_t a, const Value* _b) const
{
addr_t b = _b->base;
if (a == b)
return 0;
return a < b ? -1 : 1;
}
int Compare(const Value* a, const Value* b) const
{
return Compare(a->base, b);
}
};
typedef AVLTree<VMKernelAddressRangeTreeDefinition> VMKernelAddressRangeTree;
struct VMKernelAddressRangeGetFreeListLink {
typedef DoublyLinkedListLink<VMKernelAddressRange> Link;
inline Link* operator()(VMKernelAddressRange* range) const
{
return &range->freeListLink;
}
inline const Link* operator()(const VMKernelAddressRange* range) const
{
return &range->freeListLink;
}
};
struct VMKernelArea : VMArea, AVLTreeNode {
VMKernelArea(VMAddressSpace* addressSpace,
uint32 wiring, uint32 protection);
~VMKernelArea();
@@ -20,34 +116,15 @@ struct VMKernelArea : VMArea {
static VMKernelArea* Create(VMAddressSpace* addressSpace,
const char* name, uint32 wiring,
uint32 protection);
static VMKernelArea* CreateReserved(VMAddressSpace* addressSpace,
uint32 flags);
DoublyLinkedListLink<VMKernelArea>& AddressSpaceLink()
{ return fAddressSpaceLink; }
const DoublyLinkedListLink<VMKernelArea>& AddressSpaceLink() const
{ return fAddressSpaceLink; }
VMKernelAddressRange* Range() const
{ return fRange; }
void SetRange(VMKernelAddressRange* range)
{ fRange = range; }
private:
DoublyLinkedListLink<VMKernelArea> fAddressSpaceLink;
VMKernelAddressRange* fRange;
};
struct VMKernelAreaGetLink {
inline DoublyLinkedListLink<VMKernelArea>* operator()(
VMKernelArea* area) const
{
return &area->AddressSpaceLink();
}
inline const DoublyLinkedListLink<VMKernelArea>* operator()(
const VMKernelArea* area) const
{
return &area->AddressSpaceLink();
}
};
typedef DoublyLinkedList<VMKernelArea, VMKernelAreaGetLink> VMKernelAreaList;
#endif // VM_KERNEL_AREA_H
+13 -14
View File
@@ -41,7 +41,7 @@ is_valid_spot(addr_t base, addr_t alignedBase, addr_t size, addr_t limit)
VMUserAddressSpace::VMUserAddressSpace(team_id id, addr_t base, size_t size)
:
VMAddressSpace(id, base, size, "kernel address space"),
VMAddressSpace(id, base, size, "address space"),
fAreaHint(NULL)
{
}
@@ -118,7 +118,7 @@ VMUserAddressSpace::LookupArea(addr_t address) const
*/
status_t
VMUserAddressSpace::InsertArea(void** _address, uint32 addressSpec,
addr_t size, VMArea* _area)
size_t size, VMArea* _area)
{
VMUserArea* area = static_cast<VMUserArea*>(_area);
@@ -225,22 +225,21 @@ VMUserAddressSpace::ResizeArea(VMArea* _area, size_t newSize)
addr_t offset = area->Base() + newSize - next->Base();
if (next->Size() <= offset) {
RemoveArea(next);
free(next);
delete next;
} else {
status_t error = ResizeAreaHead(next, next->Size() - offset);
status_t error = ShrinkAreaHead(next, next->Size() - offset);
if (error != B_OK)
return error;
}
}
return ResizeAreaTail(area, newSize);
// TODO: In case of error we should undo the change to the reserved
// area.
area->SetSize(newSize);
return B_OK;
}
status_t
VMUserAddressSpace::ResizeAreaHead(VMArea* area, size_t size)
VMUserAddressSpace::ShrinkAreaHead(VMArea* area, size_t size)
{
size_t oldSize = area->Size();
if (size == oldSize)
@@ -254,7 +253,7 @@ VMUserAddressSpace::ResizeAreaHead(VMArea* area, size_t size)
status_t
VMUserAddressSpace::ResizeAreaTail(VMArea* area, size_t size)
VMUserAddressSpace::ShrinkAreaTail(VMArea* area, size_t size)
{
size_t oldSize = area->Size();
if (size == oldSize)
@@ -283,7 +282,7 @@ VMUserAddressSpace::ReserveAddressRange(void** _address, uint32 addressSpec,
status_t status = InsertArea(_address, addressSpec, size, area);
if (status != B_OK) {
free(area);
delete area;
return status;
}
@@ -316,7 +315,7 @@ VMUserAddressSpace::UnreserveAddressRange(addr_t address, size_t size)
// remove reserved range
RemoveArea(area);
Put();
free(area);
delete area;
}
}
@@ -332,7 +331,7 @@ VMUserAddressSpace::UnreserveAllAddressRanges()
if (area->id == RESERVED_AREA_ID) {
RemoveArea(area);
Put();
free(area);
delete area;
}
}
}
@@ -396,7 +395,7 @@ VMUserAddressSpace::_InsertAreaIntoReservedRegion(addr_t start, size_t size,
// the new area fully covers the reversed range
fAreas.Remove(next);
Put();
free(next);
delete next;
} else {
// resize the reserved range behind the area
next->SetBase(next->Base() + size);
@@ -556,7 +555,7 @@ second_chance:
foundSpot = true;
area->SetBase(alignedBase);
free(next);
delete next;
break;
}
+3 -7
View File
@@ -1,10 +1,6 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#ifndef VM_USER_ADDRESS_SPACE_H
#define VM_USER_ADDRESS_SPACE_H
@@ -29,13 +25,13 @@ public:
uint32 protection);
virtual void DeleteArea(VMArea* area);
virtual status_t InsertArea(void** _address, uint32 addressSpec,
addr_t size, VMArea* area);
size_t size, VMArea* area);
virtual void RemoveArea(VMArea* area);
virtual bool CanResizeArea(VMArea* area, size_t newSize);
virtual status_t ResizeArea(VMArea* area, size_t newSize);
virtual status_t ResizeAreaHead(VMArea* area, size_t size);
virtual status_t ResizeAreaTail(VMArea* area, size_t size);
virtual status_t ShrinkAreaHead(VMArea* area, size_t newSize);
virtual status_t ShrinkAreaTail(VMArea* area, size_t newSize);
virtual status_t ReserveAddressRange(void** _address,
uint32 addressSpec, size_t size,
+3 -1
View File
@@ -45,7 +45,9 @@ VMUserArea::Create(VMAddressSpace* addressSpace, const char* name,
VMUserArea::CreateReserved(VMAddressSpace* addressSpace, uint32 flags)
{
VMUserArea* area = new(nogrow) VMUserArea(addressSpace, 0, 0);
if (area != NULL)
if (area != NULL) {
area->id = RESERVED_AREA_ID;
area->protection = flags;
}
return area;
}
+5 -5
View File
@@ -338,7 +338,7 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
size_t oldSize = area->Size();
size_t newSize = address - area->Base();
status_t error = addressSpace->ResizeAreaTail(area, newSize);
status_t error = addressSpace->ShrinkAreaTail(area, newSize);
if (error != B_OK)
return error;
@@ -350,7 +350,7 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
&& list_is_empty(&cache->consumers)) {
error = cache->Resize(cache->virtual_base + newSize);
if (error != B_OK) {
addressSpace->ResizeAreaTail(area, oldSize);
addressSpace->ShrinkAreaTail(area, oldSize);
return error;
}
}
@@ -368,7 +368,7 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
vm_unmap_pages(area, oldBase, newBase - oldBase, false);
// resize the area
status_t error = addressSpace->ResizeAreaHead(area, newSize);
status_t error = addressSpace->ShrinkAreaHead(area, newSize);
if (error != B_OK)
return error;
@@ -392,7 +392,7 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
// resize the area
addr_t oldSize = area->Size();
status_t error = addressSpace->ResizeAreaTail(area, firstNewSize);
status_t error = addressSpace->ShrinkAreaTail(area, firstNewSize);
if (error != B_OK)
return error;
@@ -408,7 +408,7 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
B_EXACT_ADDRESS, area->wiring, area->protection, REGION_NO_PRIVATE_MAP,
&secondArea, area->name, false, kernel);
if (error != B_OK) {
addressSpace->ResizeAreaTail(area, oldSize);
addressSpace->ShrinkAreaTail(area, oldSize);
return error;
}