diff options
author | Wang Shilong <wangsl-fnst@cn.fujitsu.com> | 2013-04-12 08:12:17 -0400 |
---|---|---|
committer | Josef Bacik <jbacik@fusionio.com> | 2013-05-06 15:54:44 -0400 |
commit | f7f82b81d2c297a5864dcfd0a205917d3e753aba (patch) | |
tree | d5208b93d07ce88b5b66e646da7241fff45ce143 /fs/btrfs/ulist.c | |
parent | c2c71324ecb471c932bc1ff59e46ffcf82f274fc (diff) |
Btrfs: add a rb_tree to improve performance of ulist search
Walking backref tree and btrfs quota rely on ulist very much.
This patch tries to use rb_tree to speed up search time.
The original code always checks whether an element
exists before adding a new element, however it costs O(n).
I try to add a rb_tree in the ulist,this is only used to speed up
search. I also do some measurements with quota enabled.
fsstress -p 4 -n 10000
Without this path:
real 0m51.058s 2m4.745s 1m28.222s 1m5.137s
user 0m0.035s 0m0.041s 0m0.105s 0m0.100s
sys 0m12.009s 0m11.246s 0m10.901s 0m10.999s 0m11.287s
With this path:
real 0m55.295s 0m50.960s 1m2.214s 0m48.273s
user 0m0.053s 0m0.095s 0m0.135s 0m0.107s
sys 0m7.766s 0m6.013s 0m6.319s 0m6.030s 0m6.532s
After applying the patch,the execute time is down by ~42%.(11.287s->6.532s)
Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com>
Reviewed-by: Miao Xie <miaox@cn.fujitsu.com>
Reviewed-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs/ulist.c')
-rw-r--r-- | fs/btrfs/ulist.c | 58 |
1 files changed, 50 insertions, 8 deletions
diff --git a/fs/btrfs/ulist.c b/fs/btrfs/ulist.c index ddc61cad0080..7b417e20efe2 100644 --- a/fs/btrfs/ulist.c +++ b/fs/btrfs/ulist.c | |||
@@ -53,6 +53,7 @@ void ulist_init(struct ulist *ulist) | |||
53 | ulist->nnodes = 0; | 53 | ulist->nnodes = 0; |
54 | ulist->nodes = ulist->int_nodes; | 54 | ulist->nodes = ulist->int_nodes; |
55 | ulist->nodes_alloced = ULIST_SIZE; | 55 | ulist->nodes_alloced = ULIST_SIZE; |
56 | ulist->root = RB_ROOT; | ||
56 | } | 57 | } |
57 | EXPORT_SYMBOL(ulist_init); | 58 | EXPORT_SYMBOL(ulist_init); |
58 | 59 | ||
@@ -72,6 +73,7 @@ void ulist_fini(struct ulist *ulist) | |||
72 | if (ulist->nodes_alloced > ULIST_SIZE) | 73 | if (ulist->nodes_alloced > ULIST_SIZE) |
73 | kfree(ulist->nodes); | 74 | kfree(ulist->nodes); |
74 | ulist->nodes_alloced = 0; /* in case ulist_fini is called twice */ | 75 | ulist->nodes_alloced = 0; /* in case ulist_fini is called twice */ |
76 | ulist->root = RB_ROOT; | ||
75 | } | 77 | } |
76 | EXPORT_SYMBOL(ulist_fini); | 78 | EXPORT_SYMBOL(ulist_fini); |
77 | 79 | ||
@@ -123,6 +125,45 @@ void ulist_free(struct ulist *ulist) | |||
123 | } | 125 | } |
124 | EXPORT_SYMBOL(ulist_free); | 126 | EXPORT_SYMBOL(ulist_free); |
125 | 127 | ||
128 | static struct ulist_node *ulist_rbtree_search(struct ulist *ulist, u64 val) | ||
129 | { | ||
130 | struct rb_node *n = ulist->root.rb_node; | ||
131 | struct ulist_node *u = NULL; | ||
132 | |||
133 | while (n) { | ||
134 | u = rb_entry(n, struct ulist_node, rb_node); | ||
135 | if (u->val < val) | ||
136 | n = n->rb_right; | ||
137 | else if (u->val > val) | ||
138 | n = n->rb_left; | ||
139 | else | ||
140 | return u; | ||
141 | } | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
145 | static int ulist_rbtree_insert(struct ulist *ulist, struct ulist_node *ins) | ||
146 | { | ||
147 | struct rb_node **p = &ulist->root.rb_node; | ||
148 | struct rb_node *parent = NULL; | ||
149 | struct ulist_node *cur = NULL; | ||
150 | |||
151 | while (*p) { | ||
152 | parent = *p; | ||
153 | cur = rb_entry(parent, struct ulist_node, rb_node); | ||
154 | |||
155 | if (cur->val < ins->val) | ||
156 | p = &(*p)->rb_right; | ||
157 | else if (cur->val > ins->val) | ||
158 | p = &(*p)->rb_left; | ||
159 | else | ||
160 | return -EEXIST; | ||
161 | } | ||
162 | rb_link_node(&ins->rb_node, parent, p); | ||
163 | rb_insert_color(&ins->rb_node, &ulist->root); | ||
164 | return 0; | ||
165 | } | ||
166 | |||
126 | /** | 167 | /** |
127 | * ulist_add - add an element to the ulist | 168 | * ulist_add - add an element to the ulist |
128 | * @ulist: ulist to add the element to | 169 | * @ulist: ulist to add the element to |
@@ -151,14 +192,13 @@ int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask) | |||
151 | int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, | 192 | int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, |
152 | u64 *old_aux, gfp_t gfp_mask) | 193 | u64 *old_aux, gfp_t gfp_mask) |
153 | { | 194 | { |
154 | int i; | 195 | int ret = 0; |
155 | 196 | struct ulist_node *node = NULL; | |
156 | for (i = 0; i < ulist->nnodes; ++i) { | 197 | node = ulist_rbtree_search(ulist, val); |
157 | if (ulist->nodes[i].val == val) { | 198 | if (node) { |
158 | if (old_aux) | 199 | if (old_aux) |
159 | *old_aux = ulist->nodes[i].aux; | 200 | *old_aux = node->aux; |
160 | return 0; | 201 | return 0; |
161 | } | ||
162 | } | 202 | } |
163 | 203 | ||
164 | if (ulist->nnodes >= ulist->nodes_alloced) { | 204 | if (ulist->nnodes >= ulist->nodes_alloced) { |
@@ -187,6 +227,8 @@ int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, | |||
187 | } | 227 | } |
188 | ulist->nodes[ulist->nnodes].val = val; | 228 | ulist->nodes[ulist->nnodes].val = val; |
189 | ulist->nodes[ulist->nnodes].aux = aux; | 229 | ulist->nodes[ulist->nnodes].aux = aux; |
230 | ret = ulist_rbtree_insert(ulist, &ulist->nodes[ulist->nnodes]); | ||
231 | BUG_ON(ret); | ||
190 | ++ulist->nnodes; | 232 | ++ulist->nnodes; |
191 | 233 | ||
192 | return 1; | 234 | return 1; |