I haven't written anything for a long time. I 've looked at what I 've seen in the past few days, and then watched the PST implementation in the kernel in the afternoon. Because there are few authoritative analyses on the Internet, the analysis here cannot be completely correct. First look at the relevant struct:
Below is the root of PST:
struct prio_tree_root {
struct prio_tree_node *prio_tree_node;
unsigned short index_bits;
unsigned short raw;
};
Structure Embedded in vm_area_struct:
struct raw_prio_tree_node {
struct prio_tree_node *left;
struct prio_tree_node *right;
struct prio_tree_node *parent;
};
Prio_tree_node:
struct prio_tree_node {
struct prio_tree_node *left;
struct prio_tree_node *right;
struct prio_tree_node *parent;
unsigned long start;
unsigned long last;
};
The insert operation is troublesome throughout the process. This function is analyzed as follows:
struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root,struct prio_tree_node *node)
Insert the node to the root according to certain rules, and then return the node pointer. In principle, insertion should not fail. Therefore, if null is returned, a bug () occurs (). The specific rules depend on the specific implementation of the function:
unsigned long radix_index, heap_index;
unsigned long r_index, h_index, index, mask;
int size_flag = 0;
If you think of each node as a range, the range of the child node is [randix_index, heap_index], and the range of the parent is [r_index, h_index]. The get_index function is called when the interval is obtained based on node:
static void get_index(const struct prio_tree_root *root,const struct prio_tree_node *node,unsigned long *radix, unsigned long *heap)
{
if (root->raw) {
struct vm_area_struct *vma = prio_tree_entry( node, struct vm_area_struct, shared.prio_tree_node);
*radix = RADIX_INDEX(vma);
*heap = HEAP_INDEX(vma);
}
else {
*radix = node->start;
*heap = node->last;
}
}
Initialize curr, and start the actual insertion process after the mask:
cur = root->prio_tree_node;
mask = 1UL << (root->index_bits - 1);
If the current range has been saved in PST, the node is directly returned. Otherwise, the comparison of child and parent is encountered below:
if (h_index < heap_index || (h_index == heap_index && r_index > radix_index)) {
struct prio_tree_node *tmp = node;
node = prio_tree_replace(root, cur, node);
cur = tmp;
index = r_index;
r_index = radix_index;
radix_index = index;
index = h_index;
h_index = heap_index;
heap_index = index;
}
This comparison shows that the right boundary of parent is always greater than that of child (if the right boundary of parent is the same as that of child, the left boundary of parent must be smaller than that of child ). In fact, a simpler description is that if the range from the root node to the top of the leaf path is first sorted by heap_index from large to small, the intervals with the same heap_index are sorted by Radix in ascending order. There is no balance issue yet. Let's look at how to select the left and right subtree:
if (index & mask) {
if (prio_tree_right_empty(cur)) {
INIT_PRIO_TREE_NODE(node);
cur->right = node;
node->parent = cur;
return res;
} else
cur = cur->right;
} else {
if (prio_tree_left_empty(cur)) {
INIT_PRIO_TREE_NODE(node);
cur->left = node;
node->parent = cur;
return res;
} else
cur = cur->left;
}
mask >>= 1;
Index & Mask is used to check whether each bit of the index is 1. If it is 1, it goes to cur-> right; otherwise, it goes to cur-> left. Mask> = 1 we can see that it is checked in sequence from high to low (is the implementation here similar to the base tree ?), In this case, all the small ones are on the left and the big ones are on the right. The following shows where the index comes from:
if (size_flag)
index = heap_index - radix_index;
else
index = radix_index;
When the number of layers is smaller than root-> index_bits, the left boundary in left_child is always less than that in right_child. In PST, if the left boundary is the same, it is possible that the number of layers exceeds index_bits. At this time, the direction is determined based on the bits in the range length value:
if (!mask) {
mask = 1UL << (BITS_PER_LONG - 1);
size_flag = 1;
}
When the number of layers is exceeded, it is initialized to the highest bit that long can represent. In this case, the first step is to go left when the number of layers is exceeded (the probability of this case should not be particularly high ). So far, we know how data is organized in PST.
------------------------------
Welcome to shoot bricks.