Skip to content

Commit 57a869e

Browse files
authored
optimize: cached iterator object and reused it, will free it when we … (#20)
* optimize: cached iterator object and reused it, will free it when we need to destroy radixtree object.
1 parent 99b9284 commit 57a869e

File tree

6 files changed

+111
-41
lines changed

6 files changed

+111
-41
lines changed

README.md

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -151,30 +151,42 @@ make dev
151151
Benchmark
152152
=========
153153

154-
This is a test example and the result, on my laptop, a single core CPU can match 1 million times in 1.4 seconds (based on 100,000 routes).
154+
We wrote some simple benchmark scripts.
155+
Machine environment: Macbook pro 2015 15-inch i7 2.8G CPU.
155156

156157
```shell
157-
$ cat test.lua
158-
local radix = require("resty.radixtree")
159-
160-
local routes = {}
161-
for i = 1, 1000 * 100 do
162-
routes[i] = {paths = {"/" .. ngx.md5(i) .. "/*"}, metadata = i}
163-
end
164-
165-
local rx = radix.new(routes)
166-
167-
local res
168-
local uri = "/" .. ngx.md5(300) .. "/a"
169-
for _ = 1, 1000 * 1000 do
170-
res = rx:match(uri)
171-
end
172-
173-
ngx.say(res)
174-
175-
$ time resty test.lua
176-
800
177-
resty test.lua 1.31s user 0.07s system 100% cpu 1.378 total
158+
$ make
159+
cc -O2 -g -Wall -fpic -std=c99 -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -DBUILDING_SO -c src/rax.c -o src/rax.o
160+
cc -O2 -g -Wall -fpic -std=c99 -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -DBUILDING_SO -c src/easy_rax.c -o src/easy_rax.o
161+
cc -shared -fvisibility=hidden src/rax.o src/easy_rax.o -o librestyradixtree.so
162+
163+
$ resty -I./lib benchmark/match-static.lua
164+
matched res: 500
165+
route count: 100000
166+
match times: 1000000
167+
time used : 0.089999914169312 sec
168+
QPS : 11111121
169+
170+
$ resty -I./lib benchmark/match-static.lua
171+
matched res: 500
172+
route count: 100000
173+
match times: 1000000
174+
time used : 0.094000101089478 sec
175+
QPS : 10638286
176+
177+
$ resty -I./lib benchmark/match-prefix.lua
178+
matched res: 500
179+
route count: 100000
180+
match times: 1000000
181+
time used : 0.85500001907349 sec
182+
QPS : 1169590
183+
184+
$ resty -I./lib benchmark/match-prefix.lua
185+
matched res: 500
186+
route count: 100000
187+
match times: 1000000
188+
time used : 0.83500003814697 sec
189+
QPS : 1197604
178190
```
179191

180192
[Back to TOC](#table-of-contents)

benchmark/match-prefix.lua

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
local radix = require("resty.radixtree")
2+
local route_count = 1000 * 100
3+
local match_times = 1000 * 1000
4+
5+
local routes = {}
6+
for i = 1, route_count do
7+
routes[i] = {paths = {"/" .. ngx.md5(i) .. "/*"}, metadata = i}
8+
end
9+
10+
local rx = radix.new(routes)
11+
12+
ngx.update_time()
13+
local start_time = ngx.now()
14+
15+
local res
16+
local uri = "/" .. ngx.md5(500) .. "/a"
17+
for _ = 1, match_times do
18+
res = rx:match(uri)
19+
end
20+
21+
ngx.update_time()
22+
local used_time = ngx.now() - start_time
23+
ngx.say("matched res: ", res)
24+
ngx.say("route count: ", route_count)
25+
ngx.say("match times: ", match_times)
26+
ngx.say("time used : ", used_time, " sec")
27+
ngx.say("QPS : ", math.floor(match_times / used_time))

benchmark/match-static.lua

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
local radix = require("resty.radixtree")
2+
local route_count = 1000 * 100
3+
local match_times = 1000 * 1000
4+
5+
local routes = {}
6+
for i = 1, route_count do
7+
routes[i] = {paths = {"/" .. ngx.md5(i)}, metadata = i}
8+
end
9+
10+
local rx = radix.new(routes)
11+
12+
ngx.update_time()
13+
local start_time = ngx.now()
14+
15+
local res
16+
local uri = "/" .. ngx.md5(500)
17+
for _ = 1, match_times do
18+
res = rx:match(uri)
19+
end
20+
21+
ngx.update_time()
22+
local used_time = ngx.now() - start_time
23+
ngx.say("matched res: ", res)
24+
ngx.say("route count: ", route_count)
25+
ngx.say("match times: ", match_times)
26+
ngx.say("time used : ", used_time, " sec")
27+
ngx.say("QPS : ", math.floor(match_times / used_time))

lib/resty/radixtree.lua

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ ffi_cdef[[
7878
int radix_tree_pcre(void *it, const unsigned char *buf, size_t len);
7979
int radix_tree_stop(void *it);
8080
81-
void *radix_tree_new_it();
81+
void *radix_tree_new_it(void *t);
8282
]]
8383

8484

@@ -290,8 +290,15 @@ function _M.new(routes)
290290

291291
local route_n = #routes
292292

293+
local tree = radix.radix_tree_new()
294+
local tree_it = radix.radix_tree_new_it(tree)
295+
if tree_it == nil then
296+
error("failed to new radixtree iterator")
297+
end
298+
293299
local self = setmt__gc({
294-
tree = radix.radix_tree_new(),
300+
tree = tree,
301+
tree_it = tree_it,
295302
match_data_index = 0,
296303
match_data = new_tab(#routes, 0),
297304
hash_path = new_tab(0, #routes),
@@ -318,12 +325,18 @@ end -- do
318325

319326

320327
function _M.free(self)
321-
if not self.tree then
322-
return
328+
local it = self.tree_it
329+
if it then
330+
radix.radix_tree_stop(it)
331+
ffi.C.free(it)
332+
self.tree_it = nil
333+
end
334+
335+
if self.tree then
336+
radix.radix_tree_destroy(self.tree)
337+
self.tree = nil
323338
end
324339

325-
radix.radix_tree_destroy(self.tree)
326-
self.tree = nil
327340
return
328341
end
329342

@@ -481,13 +494,6 @@ local function match_route_opts(route, opts)
481494
return true
482495
end
483496

484-
local radix_it = radix.radix_tree_new_it()
485-
if radix_it == nil then
486-
error("failed to new radixtree it")
487-
end
488-
-- use gc to free
489-
ffi.gc(radix_it, ffi.C.free)
490-
491497
local function _match_from_routes(routes, path, opts)
492498
for _, route in ipairs(routes) do
493499
if route.path_op == "=" then
@@ -516,7 +522,7 @@ local function match_route(self, path, opts)
516522
end
517523
end
518524

519-
local it = radix.radix_tree_search(self.tree, radix_it, path, #path)
525+
local it = radix.radix_tree_search(self.tree, self.tree_it, path, #path)
520526
if not it then
521527
return nil, "failed to match"
522528
end
@@ -531,13 +537,11 @@ local function match_route(self, path, opts)
531537
if routes then
532538
local route = _match_from_routes(routes, path, opts)
533539
if route then
534-
radix.radix_tree_stop(it)
535540
return route
536541
end
537542
end
538543
end
539544

540-
radix.radix_tree_stop(it)
541545
return nil
542546
end
543547

src/easy_rax.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,14 @@ radix_tree_find(void *t, const unsigned char *buf, size_t len)
5757

5858

5959
void *
60-
radix_tree_new_it()
60+
radix_tree_new_it(void *t)
6161
{
6262
raxIterator *it = malloc(sizeof(raxIterator));
6363
if (it == NULL) {
6464
return NULL;
6565
}
6666

67+
raxStart(it, (rax *)t);
6768
return (void *)it;
6869
}
6970

@@ -76,7 +77,6 @@ radix_tree_search(void *t, void *it, const unsigned char *buf, size_t len)
7677
return NULL;
7778
}
7879

79-
raxStart(iter, t);
8080
raxSeek(iter, "<=", (unsigned char *)buf, len);
8181
return (void *)iter;
8282
}

src/easy_rax.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ int radix_tree_pcre(void *it, const unsigned char *buf, size_t len);
3939
int radix_tree_next(void *it, const unsigned char *buf, size_t len);
4040
int radix_tree_stop(void *it);
4141

42-
void *radix_tree_new_it();
42+
void *radix_tree_new_it(void *t);
4343

4444
#ifdef __cplusplus
4545
}

0 commit comments

Comments
 (0)