mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 01:05:29 +00:00
lib/plist.c: avoid worst case scenario in plist_add
Worst case scenario of plist_add() happens when the priority of the inserted plist_node is going to be the largest after the insertion is done. The cost is going to be more significant when the original plist is longer, because the iterator is going to traverse the whole plist to find the correct position to insert the new node. The situation can be avoided by using a reverse iterator at the same time, doing so the maximum possible number of iteration is going to shrink from N to N/2. The proposed change of plist_add pasts the test in lib/plist.c to validate its correctness, also add the worst case scenario test for plist_add() in plist_test(). The worst case test are tested with the size of test_data and test_node growing from 200 to 1000. The result are showned in the following table, in which we can observed that the proposed change of plist_add performs better than the original version, and the difference between these two implementations are more significant with the size of N growing. The random case test [1], and best case test [2] are also provided, with result showing the proposed change performs slightly better in random case test while the original implementation performs slightly better in best case test, while the difference in both test are minor, we can see them as even in those two situations. ----------------------------------------------------------- | Test size | 200 | 400 | 600 | 800 | 1000 | ----------------------------------------------------------- | new_plist_add | 140911| 548681| 1220512| 2048493| 3763755| ----------------------------------------------------------- | old_plist_add | 188198| 774222| 1643547| 3008929| 4947435| ----------------------------------------------------------- Link: https://lkml.kernel.org/r/20240614154603.65203-1-richard120310@gmail.com Signed-off-by: I Hsin Cheng <richard120310@gmail.com> Signed-off-by: Ching-Chun (Jim) Huang <jserv@ccns.ncku.edu.tw> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
abd8ac0557
commit
c8dab79f9e
38
lib/plist.c
38
lib/plist.c
@ -72,7 +72,7 @@ static void plist_check_head(struct plist_head *head)
|
|||||||
*/
|
*/
|
||||||
void plist_add(struct plist_node *node, struct plist_head *head)
|
void plist_add(struct plist_node *node, struct plist_head *head)
|
||||||
{
|
{
|
||||||
struct plist_node *first, *iter, *prev = NULL;
|
struct plist_node *first, *iter, *prev = NULL, *last, *reverse_iter;
|
||||||
struct list_head *node_next = &head->node_list;
|
struct list_head *node_next = &head->node_list;
|
||||||
|
|
||||||
plist_check_head(head);
|
plist_check_head(head);
|
||||||
@ -83,16 +83,26 @@ void plist_add(struct plist_node *node, struct plist_head *head)
|
|||||||
goto ins_node;
|
goto ins_node;
|
||||||
|
|
||||||
first = iter = plist_first(head);
|
first = iter = plist_first(head);
|
||||||
|
last = reverse_iter = list_entry(first->prio_list.prev, struct plist_node, prio_list);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (node->prio < iter->prio) {
|
if (node->prio < iter->prio) {
|
||||||
node_next = &iter->node_list;
|
node_next = &iter->node_list;
|
||||||
break;
|
break;
|
||||||
|
} else if (node->prio >= reverse_iter->prio) {
|
||||||
|
prev = reverse_iter;
|
||||||
|
iter = list_entry(reverse_iter->prio_list.next,
|
||||||
|
struct plist_node, prio_list);
|
||||||
|
if (likely(reverse_iter != last))
|
||||||
|
node_next = &iter->node_list;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = iter;
|
prev = iter;
|
||||||
iter = list_entry(iter->prio_list.next,
|
iter = list_entry(iter->prio_list.next,
|
||||||
struct plist_node, prio_list);
|
struct plist_node, prio_list);
|
||||||
|
reverse_iter = list_entry(reverse_iter->prio_list.prev,
|
||||||
|
struct plist_node, prio_list);
|
||||||
} while (iter != first);
|
} while (iter != first);
|
||||||
|
|
||||||
if (!prev || prev->prio != node->prio)
|
if (!prev || prev->prio != node->prio)
|
||||||
@ -255,6 +265,32 @@ static int __init plist_test(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printk(KERN_DEBUG "end plist test\n");
|
printk(KERN_DEBUG "end plist test\n");
|
||||||
|
|
||||||
|
/* Worst case test for plist_add() */
|
||||||
|
unsigned int test_data[241];
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(test_data); i++)
|
||||||
|
test_data[i] = i;
|
||||||
|
|
||||||
|
ktime_t start, end, time_elapsed = 0;
|
||||||
|
|
||||||
|
plist_head_init(&test_head);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(test_node); i++) {
|
||||||
|
plist_node_init(test_node + i, 0);
|
||||||
|
test_node[i].prio = test_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(test_node); i++) {
|
||||||
|
if (plist_node_empty(test_node + i)) {
|
||||||
|
start = ktime_get();
|
||||||
|
plist_add(test_node + i, &test_head);
|
||||||
|
end = ktime_get();
|
||||||
|
time_elapsed += (end - start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_debug("plist_add worst case test time elapsed %lld\n", time_elapsed);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user