2019-05-19 15:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-10-09 03:30:39 +04:00
# include <linux/module.h>
2017-09-09 02:14:46 +03:00
# include <linux/moduleparam.h>
2012-10-09 03:31:33 +04:00
# include <linux/rbtree_augmented.h>
2012-10-09 03:30:39 +04:00
# include <linux/random.h>
2017-09-09 02:14:46 +03:00
# include <linux/slab.h>
2012-10-09 03:30:39 +04:00
# include <asm/timex.h>
2017-09-09 02:14:46 +03:00
# define __param(type, name, init, msg) \
static type name = init ; \
module_param ( name , type , 0444 ) ; \
MODULE_PARM_DESC ( name , msg ) ;
__param ( int , nnodes , 100 , " Number of nodes in the rb-tree " ) ;
2017-11-18 02:28:27 +03:00
__param ( int , perf_loops , 1000 , " Number of iterations modifying the rb-tree " ) ;
2017-09-09 02:14:46 +03:00
__param ( int , check_loops , 100 , " Number of iterations modifying and verifying the rb-tree " ) ;
2012-10-09 03:30:39 +04:00
struct test_node {
u32 key ;
2014-01-24 03:56:05 +04:00
struct rb_node rb ;
2012-10-09 03:31:15 +04:00
/* following fields used for testing augmented rbtree functionality */
u32 val ;
u32 augmented ;
2012-10-09 03:30:39 +04:00
} ;
2017-09-09 02:14:52 +03:00
static struct rb_root_cached root = RB_ROOT_CACHED ;
2017-09-09 02:14:46 +03:00
static struct test_node * nodes = NULL ;
2012-10-09 03:30:39 +04:00
static struct rnd_state rnd ;
2017-09-09 02:14:52 +03:00
static void insert ( struct test_node * node , struct rb_root_cached * root )
2012-10-09 03:30:39 +04:00
{
2017-09-09 02:14:52 +03:00
struct rb_node * * new = & root - > rb_root . rb_node , * parent = NULL ;
2012-10-09 03:31:15 +04:00
u32 key = node - > key ;
2012-10-09 03:30:39 +04:00
while ( * new ) {
parent = * new ;
2012-10-09 03:31:15 +04:00
if ( key < rb_entry ( parent , struct test_node , rb ) - > key )
2012-10-09 03:30:39 +04:00
new = & parent - > rb_left ;
else
new = & parent - > rb_right ;
}
rb_link_node ( & node - > rb , parent , new ) ;
2017-09-09 02:14:52 +03:00
rb_insert_color ( & node - > rb , & root - > rb_root ) ;
2012-10-09 03:30:39 +04:00
}
2017-09-09 02:14:52 +03:00
static void insert_cached ( struct test_node * node , struct rb_root_cached * root )
2012-10-09 03:30:39 +04:00
{
2017-09-09 02:14:52 +03:00
struct rb_node * * new = & root - > rb_root . rb_node , * parent = NULL ;
u32 key = node - > key ;
bool leftmost = true ;
while ( * new ) {
parent = * new ;
if ( key < rb_entry ( parent , struct test_node , rb ) - > key )
new = & parent - > rb_left ;
else {
new = & parent - > rb_right ;
leftmost = false ;
}
}
rb_link_node ( & node - > rb , parent , new ) ;
rb_insert_color_cached ( & node - > rb , root , leftmost ) ;
2012-10-09 03:30:39 +04:00
}
2017-09-09 02:14:52 +03:00
static inline void erase ( struct test_node * node , struct rb_root_cached * root )
{
rb_erase ( & node - > rb , & root - > rb_root ) ;
}
static inline void erase_cached ( struct test_node * node , struct rb_root_cached * root )
{
rb_erase_cached ( & node - > rb , root ) ;
}
2012-10-09 03:31:15 +04:00
static inline u32 augment_recompute ( struct test_node * node )
{
u32 max = node - > val , child_augmented ;
if ( node - > rb . rb_left ) {
child_augmented = rb_entry ( node - > rb . rb_left , struct test_node ,
rb ) - > augmented ;
if ( max < child_augmented )
max = child_augmented ;
}
if ( node - > rb . rb_right ) {
child_augmented = rb_entry ( node - > rb . rb_right , struct test_node ,
rb ) - > augmented ;
if ( max < child_augmented )
max = child_augmented ;
}
return max ;
}
2012-10-09 03:31:21 +04:00
RB_DECLARE_CALLBACKS ( static , augment_callbacks , struct test_node , rb ,
u32 , augmented , augment_recompute )
2012-10-09 03:31:17 +04:00
2017-09-09 02:14:52 +03:00
static void insert_augmented ( struct test_node * node ,
struct rb_root_cached * root )
2012-10-09 03:31:15 +04:00
{
2017-09-09 02:14:52 +03:00
struct rb_node * * new = & root - > rb_root . rb_node , * rb_parent = NULL ;
2012-10-09 03:31:15 +04:00
u32 key = node - > key ;
2012-10-09 03:31:17 +04:00
u32 val = node - > val ;
struct test_node * parent ;
2012-10-09 03:31:15 +04:00
while ( * new ) {
2012-10-09 03:31:17 +04:00
rb_parent = * new ;
parent = rb_entry ( rb_parent , struct test_node , rb ) ;
if ( parent - > augmented < val )
parent - > augmented = val ;
if ( key < parent - > key )
new = & parent - > rb . rb_left ;
2012-10-09 03:31:15 +04:00
else
2012-10-09 03:31:17 +04:00
new = & parent - > rb . rb_right ;
2012-10-09 03:31:15 +04:00
}
2012-10-09 03:31:17 +04:00
node - > augmented = val ;
rb_link_node ( & node - > rb , rb_parent , new ) ;
2017-09-09 02:14:52 +03:00
rb_insert_augmented ( & node - > rb , & root - > rb_root , & augment_callbacks ) ;
}
static void insert_augmented_cached ( struct test_node * node ,
struct rb_root_cached * root )
{
struct rb_node * * new = & root - > rb_root . rb_node , * rb_parent = NULL ;
u32 key = node - > key ;
u32 val = node - > val ;
struct test_node * parent ;
bool leftmost = true ;
while ( * new ) {
rb_parent = * new ;
parent = rb_entry ( rb_parent , struct test_node , rb ) ;
if ( parent - > augmented < val )
parent - > augmented = val ;
if ( key < parent - > key )
new = & parent - > rb . rb_left ;
else {
new = & parent - > rb . rb_right ;
leftmost = false ;
}
}
node - > augmented = val ;
rb_link_node ( & node - > rb , rb_parent , new ) ;
rb_insert_augmented_cached ( & node - > rb , root ,
leftmost , & augment_callbacks ) ;
}
static void erase_augmented ( struct test_node * node , struct rb_root_cached * root )
{
rb_erase_augmented ( & node - > rb , & root - > rb_root , & augment_callbacks ) ;
2012-10-09 03:31:15 +04:00
}
2017-09-09 02:14:52 +03:00
static void erase_augmented_cached ( struct test_node * node ,
struct rb_root_cached * root )
2012-10-09 03:31:15 +04:00
{
2017-09-09 02:14:52 +03:00
rb_erase_augmented_cached ( & node - > rb , root , & augment_callbacks ) ;
2012-10-09 03:31:15 +04:00
}
2012-10-09 03:30:39 +04:00
static void init ( void )
{
int i ;
2017-09-09 02:14:46 +03:00
for ( i = 0 ; i < nnodes ; i + + ) {
2012-12-18 04:04:23 +04:00
nodes [ i ] . key = prandom_u32_state ( & rnd ) ;
nodes [ i ] . val = prandom_u32_state ( & rnd ) ;
2012-10-09 03:31:15 +04:00
}
2012-10-09 03:30:39 +04:00
}
static bool is_red ( struct rb_node * rb )
{
return ! ( rb - > __rb_parent_color & 1 ) ;
}
static int black_path_count ( struct rb_node * rb )
{
int count ;
for ( count = 0 ; rb ; rb = rb_parent ( rb ) )
count + = ! is_red ( rb ) ;
return count ;
}
2014-01-24 03:56:06 +04:00
static void check_postorder_foreach ( int nr_nodes )
{
struct test_node * cur , * n ;
int count = 0 ;
2017-09-09 02:14:52 +03:00
rbtree_postorder_for_each_entry_safe ( cur , n , & root . rb_root , rb )
2014-01-24 03:56:06 +04:00
count + + ;
WARN_ON_ONCE ( count ! = nr_nodes ) ;
}
2013-09-12 01:25:17 +04:00
static void check_postorder ( int nr_nodes )
{
struct rb_node * rb ;
int count = 0 ;
2017-09-09 02:14:52 +03:00
for ( rb = rb_first_postorder ( & root . rb_root ) ; rb ; rb = rb_next_postorder ( rb ) )
2013-09-12 01:25:17 +04:00
count + + ;
WARN_ON_ONCE ( count ! = nr_nodes ) ;
}
2012-10-09 03:30:39 +04:00
static void check ( int nr_nodes )
{
struct rb_node * rb ;
2013-05-01 02:28:24 +04:00
int count = 0 , blacks = 0 ;
2012-10-09 03:30:39 +04:00
u32 prev_key = 0 ;
2017-09-09 02:14:52 +03:00
for ( rb = rb_first ( & root . rb_root ) ; rb ; rb = rb_next ( rb ) ) {
2012-10-09 03:30:39 +04:00
struct test_node * node = rb_entry ( rb , struct test_node , rb ) ;
WARN_ON_ONCE ( node - > key < prev_key ) ;
WARN_ON_ONCE ( is_red ( rb ) & &
( ! rb_parent ( rb ) | | is_red ( rb_parent ( rb ) ) ) ) ;
if ( ! count )
blacks = black_path_count ( rb ) ;
else
WARN_ON_ONCE ( ( ! rb - > rb_left | | ! rb - > rb_right ) & &
blacks ! = black_path_count ( rb ) ) ;
prev_key = node - > key ;
count + + ;
}
2013-05-01 02:28:24 +04:00
2012-10-09 03:30:39 +04:00
WARN_ON_ONCE ( count ! = nr_nodes ) ;
2017-09-09 02:14:52 +03:00
WARN_ON_ONCE ( count < ( 1 < < black_path_count ( rb_last ( & root . rb_root ) ) ) - 1 ) ;
2013-09-12 01:25:17 +04:00
check_postorder ( nr_nodes ) ;
2014-01-24 03:56:06 +04:00
check_postorder_foreach ( nr_nodes ) ;
2012-10-09 03:30:39 +04:00
}
2012-10-09 03:31:15 +04:00
static void check_augmented ( int nr_nodes )
{
struct rb_node * rb ;
check ( nr_nodes ) ;
2017-09-09 02:14:52 +03:00
for ( rb = rb_first ( & root . rb_root ) ; rb ; rb = rb_next ( rb ) ) {
2012-10-09 03:31:15 +04:00
struct test_node * node = rb_entry ( rb , struct test_node , rb ) ;
WARN_ON_ONCE ( node - > augmented ! = augment_recompute ( node ) ) ;
}
}
2013-05-01 02:28:25 +04:00
static int __init rbtree_test_init ( void )
2012-10-09 03:30:39 +04:00
{
int i , j ;
cycles_t time1 , time2 , time ;
2017-09-09 02:14:49 +03:00
struct rb_node * node ;
2012-10-09 03:30:39 +04:00
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 23:55:00 +03:00
nodes = kmalloc_array ( nnodes , sizeof ( * nodes ) , GFP_KERNEL ) ;
2017-09-09 02:14:46 +03:00
if ( ! nodes )
return - ENOMEM ;
2012-10-09 03:30:39 +04:00
printk ( KERN_ALERT " rbtree testing " ) ;
2012-12-18 04:04:23 +04:00
prandom_seed_state ( & rnd , 3141592653589793238ULL ) ;
2012-10-09 03:30:39 +04:00
init ( ) ;
time1 = get_cycles ( ) ;
2017-09-09 02:14:46 +03:00
for ( i = 0 ; i < perf_loops ; i + + ) {
for ( j = 0 ; j < nnodes ; j + + )
2012-10-09 03:30:39 +04:00
insert ( nodes + j , & root ) ;
2017-09-09 02:14:46 +03:00
for ( j = 0 ; j < nnodes ; j + + )
2012-10-09 03:30:39 +04:00
erase ( nodes + j , & root ) ;
}
time2 = get_cycles ( ) ;
time = time2 - time1 ;
2017-09-09 02:14:46 +03:00
time = div_u64 ( time , perf_loops ) ;
2017-09-09 02:14:52 +03:00
printk ( " -> test 1 (latency of nnodes insert+delete): %llu cycles \n " ,
( unsigned long long ) time ) ;
time1 = get_cycles ( ) ;
for ( i = 0 ; i < perf_loops ; i + + ) {
for ( j = 0 ; j < nnodes ; j + + )
insert_cached ( nodes + j , & root ) ;
for ( j = 0 ; j < nnodes ; j + + )
erase_cached ( nodes + j , & root ) ;
}
time2 = get_cycles ( ) ;
time = time2 - time1 ;
time = div_u64 ( time , perf_loops ) ;
printk ( " -> test 2 (latency of nnodes cached insert+delete): %llu cycles \n " ,
( unsigned long long ) time ) ;
2012-10-09 03:30:39 +04:00
2017-09-09 02:14:49 +03:00
for ( i = 0 ; i < nnodes ; i + + )
insert ( nodes + i , & root ) ;
time1 = get_cycles ( ) ;
for ( i = 0 ; i < perf_loops ; i + + ) {
2017-09-09 02:14:52 +03:00
for ( node = rb_first ( & root . rb_root ) ; node ; node = rb_next ( node ) )
2017-09-09 02:14:49 +03:00
;
}
time2 = get_cycles ( ) ;
time = time2 - time1 ;
time = div_u64 ( time , perf_loops ) ;
2017-09-09 02:14:52 +03:00
printk ( " -> test 3 (latency of inorder traversal): %llu cycles \n " ,
( unsigned long long ) time ) ;
time1 = get_cycles ( ) ;
for ( i = 0 ; i < perf_loops ; i + + )
node = rb_first ( & root . rb_root ) ;
time2 = get_cycles ( ) ;
time = time2 - time1 ;
time = div_u64 ( time , perf_loops ) ;
printk ( " -> test 4 (latency to fetch first node) \n " ) ;
printk ( " non-cached: %llu cycles \n " , ( unsigned long long ) time ) ;
time1 = get_cycles ( ) ;
for ( i = 0 ; i < perf_loops ; i + + )
node = rb_first_cached ( & root ) ;
time2 = get_cycles ( ) ;
time = time2 - time1 ;
time = div_u64 ( time , perf_loops ) ;
printk ( " cached: %llu cycles \n " , ( unsigned long long ) time ) ;
2017-09-09 02:14:49 +03:00
for ( i = 0 ; i < nnodes ; i + + )
erase ( nodes + i , & root ) ;
/* run checks */
2017-09-09 02:14:46 +03:00
for ( i = 0 ; i < check_loops ; i + + ) {
2012-10-09 03:30:39 +04:00
init ( ) ;
2017-09-09 02:14:46 +03:00
for ( j = 0 ; j < nnodes ; j + + ) {
2012-10-09 03:30:39 +04:00
check ( j ) ;
insert ( nodes + j , & root ) ;
}
2017-09-09 02:14:46 +03:00
for ( j = 0 ; j < nnodes ; j + + ) {
check ( nnodes - j ) ;
2012-10-09 03:30:39 +04:00
erase ( nodes + j , & root ) ;
}
check ( 0 ) ;
}
2012-10-09 03:31:15 +04:00
printk ( KERN_ALERT " augmented rbtree testing " ) ;
init ( ) ;
time1 = get_cycles ( ) ;
2017-09-09 02:14:46 +03:00
for ( i = 0 ; i < perf_loops ; i + + ) {
for ( j = 0 ; j < nnodes ; j + + )
2012-10-09 03:31:15 +04:00
insert_augmented ( nodes + j , & root ) ;
2017-09-09 02:14:46 +03:00
for ( j = 0 ; j < nnodes ; j + + )
2012-10-09 03:31:15 +04:00
erase_augmented ( nodes + j , & root ) ;
}
time2 = get_cycles ( ) ;
time = time2 - time1 ;
2017-09-09 02:14:46 +03:00
time = div_u64 ( time , perf_loops ) ;
2017-09-09 02:14:49 +03:00
printk ( " -> test 1 (latency of nnodes insert+delete): %llu cycles \n " , ( unsigned long long ) time ) ;
2012-10-09 03:31:15 +04:00
2017-09-09 02:14:52 +03:00
time1 = get_cycles ( ) ;
for ( i = 0 ; i < perf_loops ; i + + ) {
for ( j = 0 ; j < nnodes ; j + + )
insert_augmented_cached ( nodes + j , & root ) ;
for ( j = 0 ; j < nnodes ; j + + )
erase_augmented_cached ( nodes + j , & root ) ;
}
time2 = get_cycles ( ) ;
time = time2 - time1 ;
time = div_u64 ( time , perf_loops ) ;
printk ( " -> test 2 (latency of nnodes cached insert+delete): %llu cycles \n " , ( unsigned long long ) time ) ;
2017-09-09 02:14:46 +03:00
for ( i = 0 ; i < check_loops ; i + + ) {
2012-10-09 03:31:15 +04:00
init ( ) ;
2017-09-09 02:14:46 +03:00
for ( j = 0 ; j < nnodes ; j + + ) {
2012-10-09 03:31:15 +04:00
check_augmented ( j ) ;
insert_augmented ( nodes + j , & root ) ;
}
2017-09-09 02:14:46 +03:00
for ( j = 0 ; j < nnodes ; j + + ) {
check_augmented ( nnodes - j ) ;
2012-10-09 03:31:15 +04:00
erase_augmented ( nodes + j , & root ) ;
}
check_augmented ( 0 ) ;
}
2017-09-09 02:14:46 +03:00
kfree ( nodes ) ;
2012-10-09 03:30:39 +04:00
return - EAGAIN ; /* Fail will directly unload the module */
}
2013-05-01 02:28:25 +04:00
static void __exit rbtree_test_exit ( void )
2012-10-09 03:30:39 +04:00
{
printk ( KERN_ALERT " test exit \n " ) ;
}
module_init ( rbtree_test_init )
module_exit ( rbtree_test_exit )
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Michel Lespinasse " ) ;
MODULE_DESCRIPTION ( " Red Black Tree test " ) ;