Skip to content

Commit 81a6a2a

Browse files
[documentation]: Add IntervalTree documentation
* Started the design and documentation of IntervalTree component of the AddressAllocator. Signed-off-by: AlexandruCihodaru <[email protected]> Co-authored-by: Liu Jiang <[email protected]>
1 parent cd82c99 commit 81a6a2a

File tree

2 files changed

+170
-0
lines changed

2 files changed

+170
-0
lines changed

images/allocation_example.png

44.1 KB
Loading

src/allocation_engine/README.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# Design
2+
3+
## Allocation engine
4+
5+
This implementation uses an interval tree that is specialised for allocation of
6+
memory-mapped I/O and port I/O address space. The fields of the strctures
7+
defined will have semantic meaning for this context (e.g node state to indicate
8+
if a node in the tree is assigned or not to a device).
9+
10+
We offer three options for placing a memory slot in the managed address space:
11+
12+
1. `LastMatch` -> When using this allocation policy the allocator will try to
13+
insert the range described by the constraint at the first available position
14+
starting from the end of the managed address space.
15+
2. `FirstMatch` -> When using this allocation policy the allocator will try to
16+
insert the range described by the constraint at the first available position
17+
starting from the begining of the managed address space.
18+
3. `ExactMatch` -> When using this allocation policy the allocator will try to
19+
insert the range at the exact position described by the constraint, otherwise
20+
it will return an error.
21+
22+
```rust
23+
/// Policy for resource allocation.
24+
pub enum AllocPolicy {
25+
/// Allocate from the first matched entry.
26+
FirstMatch,
27+
/// Allocate first matched entry from the end of the range.
28+
LastMatch,
29+
// Allocate a memory slot starting with the specified addrres
30+
// if it is available.
31+
ExactMatch,
32+
}
33+
```
34+
35+
Struct `Constraint` is used to describe the overall information of the resource
36+
needed to be allocated. This structure is also used by IntervalTree to know where
37+
and how to allocate the resource.
38+
39+
```rust
40+
/// Struct to describe resource allocation constraints.
41+
pub struct Constraint {
42+
/// Size to allocate.
43+
pub size: u64,
44+
/// Lower boundary for the allocated resource.
45+
pub min: u64,
46+
/// Upper boundary for the allocated resource.
47+
pub max: u64,
48+
/// Alignment for the allocated resource.
49+
pub align: u64,
50+
/// Resource allocation policy.
51+
pub policy: AllocPolicy,
52+
}
53+
```
54+
55+
## Interval tree
56+
57+
An interval tree is a tree data structure used for storing information about intervals.
58+
Specifically, it allows one to efficiently identify intervals that are overlaping
59+
with a given point, or another interval. We considered that this characteristic
60+
makes this data structure appropriate to be used as an allocation engine for
61+
memory slots inside an address space. The time complexity of an interval tree,
62+
namely O(log ⁡n+m) for queries, O(log n) for creation and O(log n) for insertion
63+
and deletion of nodes.
64+
65+
```rust
66+
/// A closed interval range [min, max] used to describe a
67+
/// memory slot that will be assigned to a device by the VMM.
68+
/// This structure represents the key of the Node object in
69+
/// the interval tree implementation.
70+
pub struct Range {
71+
pub min: u64,
72+
pub max: u64,
73+
}
74+
75+
/// Node state for interval tree nodes.
76+
///
77+
/// Valid state transition:
78+
/// - None -> Free: IntervalTree::insert(key, NodeState::Free)
79+
/// - Free -> Allocated: IntervalTree::insert(key, NodeState::Allocated)
80+
/// - Allocated -> Free: IntervalTree::free()
81+
/// - * -> None: IntervalTree::delete()
82+
pub enum NodeState {
83+
/// Node is free.
84+
Free,
85+
/// Node is allocated.
86+
Allocated,
87+
}
88+
89+
/// Internal tree node to implement interval tree.
90+
pub(crate) struct InnerNode {
91+
/// Interval handled by this node.
92+
pub(crate) key: Range,
93+
/// State of the node, this can be `Free` or `Allocated`
94+
pub(crate) node_state: NodeState,
95+
/// Optional left child of current node.
96+
pub(crate) left: Option<Box<InnerNode>>,
97+
/// Optional right child of current node.
98+
pub(crate) right: Option<Box<InnerNode>>,
99+
/// Cached height of the node.
100+
pub(crate) height: u64,
101+
/// Cached maximum valued covered by this node.
102+
pub(crate) max_key: u64,
103+
}
104+
```
105+
106+
## Usage
107+
108+
The concept of Interval Tree may seem complicated, but using vm-allocator to do
109+
resource allocation and release is simple and straightforward.
110+
111+
To use the `IntervalTree` implementation as an address allocator one should first
112+
create an interval tree object and give an address space as a root node.
113+
114+
```rust
115+
pub struct AddressAllocator {
116+
base: u64,
117+
end: u64,
118+
interval_tree: IntervalTree,
119+
}
120+
121+
impl AddressAllocator {
122+
pub fn new(base: u64, size: u64) -> std::result::Result<Self, Error> {
123+
let interval_tree = IntervalTree::new();
124+
let end = base.checked_add(size - 1)?;
125+
let mut address_allocator = AddressAllocator {
126+
base: base,
127+
end: end,
128+
interval_tree: interval_tree,
129+
};
130+
131+
address_allocator
132+
.interval_tree
133+
.insert(Range::new(base, end)?, NodeState::Free)?;
134+
Ok(address_allocator)
135+
}
136+
```
137+
138+
After, the user should create a constraint with the size for the resource, optionally
139+
the constraint could also contain the maximum, minimum and alignment for the
140+
constraint.
141+
142+
```rust
143+
pub fn allocate(
144+
&mut self,
145+
_address: Option<u64>,
146+
size: u64,
147+
align_size: Option<u64>,
148+
alloc_policy: AllocPolicy,
149+
) -> Result<Range> {
150+
let constraint = Constraint::new(size).align(alignment).policy(alloc_policy);
151+
// some other code here
152+
if logical_condition {
153+
let key = self.interval_tree.find_candidate(&constaint);
154+
self.interval_tree.insert(key, NodeState::Allocated);
155+
}
156+
}
157+
```
158+
159+
![Allocation example](/images/allocation_example.png)
160+
161+
## License
162+
163+
**!!!NOTICE**: The BSD-3-Clause license is not included in this template.
164+
The license needs to be manually added because the text of the license file
165+
also includes the copyright. The copyright can be different for different
166+
crates. If the crate contains code from CrosVM, the crate must add the
167+
CrosVM copyright which can be found
168+
[here](https://chromium.googlesource.com/chromiumos/platform/crosvm/+/master/LICENSE).
169+
For crates developed from scratch, the copyright is different and depends on
170+
the contributors.

0 commit comments

Comments
 (0)