Document the O(log n) algorithm for finding free space.

Submitted by: Mark W. Krentel
This commit is contained in:
Alan Cox 2004-09-27 04:22:41 +00:00
parent 0a7c173775
commit af3db1449f
2 changed files with 234 additions and 0 deletions

View File

@ -252,6 +252,7 @@ MAN= accept_filter.9 \
vm_map_clean.9 \
vm_map_create.9 \
vm_map_delete.9 \
vm_map_entry_resize_free.9 \
vm_map_find.9 \
vm_map_findspace.9 \
vm_map_inherit.9 \

View File

@ -0,0 +1,233 @@
.\"
.\" Copyright (c) 2004 Mark W. Krentel <krentel@dreamscape.com>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd August 17, 2004
.Os
.Dt VM_MAP_ENTRY_RESIZE_FREE 9
.Sh NAME
.Nm vm_map_entry_resize_free
.Nd vm map free space algorithm
.Sh SYNOPSIS
.In sys/param.h
.In vm/vm.h
.In vm/vm_map.h
.Ft void
.Fo vm_map_entry_resize_free
.Fa "vm_map_t map" "vm_map_entry_t entry"
.Fc
.Sh DESCRIPTION
This manual page describes the
.Vt vm_map_entry
fields used in the VM map free space algorithm, how to maintain
consistency of these variables, and the
.Fn vm_map_entry_resize_free
function.
.Pp
VM map entries are organized as both a doubly-linked list
.Va ( prev
and
.Va next
pointers) and as a binary search tree
.Va ( left
and
.Va right
pointers).
The search tree is organized as a Sleator and Tarjan splay tree,
also known as a
.Dq self-adjusting tree.
.Bd -literal -offset indent
struct vm_map_entry {
struct vm_map_entry *prev;
struct vm_map_entry *next;
struct vm_map_entry *left;
struct vm_map_entry *right;
vm_offset_t start;
vm_offset_t end;
vm_offset_t avail_ssize;
vm_size_t adj_free;
vm_size_t max_free;
...
};
.Ed
.Pp
The free space algorithm adds two fields to
.Vt struct vm_map_entry :
.Va adj_free
and
.Va max_free .
.Va adj_free
is the amount of free address space adjacent to and immediately
following (higher address) the map entry.
This field is unused in the map header.
Note that
.Va adj_free
depends on the linked list, not the splay tree and that
.Va adj_free
can be computed as:
.Bd -literal -offset indent
entry->adj_free = (entry->next == &map->header ?
map->max_offset : entry->next->start) - entry->end;
.Ed
.Pp
.Va max_free
is the maximum amount of contiguous free space in the entry's subtree.
Note that
.Va max_free
depends on the splay tree, not the linked list and that
.Va max_free
is computed by taking the maximum of its own
.Va adj_free
and the
.Va max_free
of its left and right subtrees.
Again,
.Va max_free
is unused in the map header.
.Pp
These fields allow for an O(log\~n) implementation of
.Fn vm_map_findspace .
Using
.Va max_free ,
we can immediately test for a sufficiently large free region
in an entire subtree.
This makes it possible to find a first-fit free region of a given size
in one pass down the tree, so O(log\~n) amortized using splay trees.
.Pp
When a free region changes size, we must update
.Va adj_free
and
.Va max_free
in the preceding map entry and propagate
.Va max_free
up the tree.
This is handled in
.Fn vm_map_entry_link
and
.Fn vm_map_entry_unlink
for the cases of inserting and deleting an entry.
Note that
.Fn vm_map_entry_link
updates both the new entry and the previous entry, and that
.Fn vm_map_entry_unlink
updates the previous entry.
Also note that
.Va max_free
is not actually propagated up the tree.
Instead, that entry is first splayed to the root and
then the change is made there.
This is a common technique in splay trees and is also
how map entries are linked and unlinked into the tree.
.Pp
The
.Fn vm_map_entry_resize_free
function updates the free space variables in the given
.Fa entry
and propagates those values up the tree.
This function should be called whenever a map entry is resized
in-place, that is, by modifying its
.Va start
or
.Va end
values.
Note that if you change
.Va end ,
then you should resize that entry, but if you change
.Va start ,
then you should resize the previous entry.
The map must be locked before calling this function,
and again, propagating
.Va max_free
is performed by splaying that entry to the root.
.Sh EXAMPLES
Consider adding a map entry with
.Fn vm_map_insert .
.Bd -literal -offset indent
ret = vm_map_insert(map, object, offset, start, end, prot,
max_prot, cow);
.Ed
.Pp
In this case, no further action is required to maintain
consistency of the free space variables.
.Fn vm_map_insert
calls
.Fn vm_map_entry_link
which updates both the new entry and the previous entry.
The same would be true for
.Fn vm_map_delete
and for calling
.Fn vm_map_entry_link
or
.Fn vm_map_entry_unlink
directly.
.Pp
Now consider resizing an entry in-place without a call to
.Fn vm_map_entry_link
or
.Fn vm_map_entry_unlink .
.Bd -literal -offset indent
entry->start = new_start;
if (entry->prev != &map->header)
vm_map_entry_resize_free(map, entry->prev);
.Ed
.Pp
In this case, resetting
.Va start
changes the amount of free space following the previous entry,
so we use
.Fn vm_map_entry_resize_free
to update the previous entry.
.Pp
Finally, suppose we change an entry's
.Va end
address.
.Bd -literal -offset indent
entry->end = new_end;
vm_map_entry_resize_free(map, entry);
.Ed
.Pp
Here, we call
.Fn vm_map_entry_resize_free
on the entry itself.
.Sh SEE ALSO
.Xr vm_map 9 ,
.Xr vm_map_findspace 9
.Rs
.%A Daniel D. Sleator
.%A Robert E. Tarjan
.%T Self-Adjusting Binary Search Trees
.%J JACM
.%V vol. 32(3)
.%P pp. 652-686
.%D July 1985
.Re
.Sh HISTORY
Splay trees were added to the VM map in FreeBSD 5.0, and the
O(log\~n) tree-based free space algorithm was added in FreeBSD 5.3.
.Sh AUTHORS
The tree-based free space algorithm and this manual page were written by
.An Mark W. Krentel
.Aq krentel@dreamscape.com .