Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
timeout.c
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kirill Smelkov
timeout.c
Commits
a605dc78
Commit
a605dc78
authored
Feb 02, 2014
by
william
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add llrb test
parent
cc8d1f97
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
432 additions
and
4 deletions
+432
-4
Makefile
Makefile
+2
-2
bench-llrb.c
bench-llrb.c
+418
-0
bench.c
bench.c
+12
-2
No files found.
Makefile
View file @
a605dc78
all
:
bench bench-wheel.so bench-heap.so
all
:
bench
.so
bench-wheel.so bench-heap.so
WHEEL_BIT
=
6
WHEEL_BIT
=
6
WHEEL_NUM
=
4
WHEEL_NUM
=
4
...
@@ -68,7 +68,7 @@ bench-%.so: bench-%.c timeout.h
...
@@ -68,7 +68,7 @@ bench-%.so: bench-%.c timeout.h
.PHONY
:
clean clean~
.PHONY
:
clean clean~
clean
:
clean
:
$(RM)
-r
timeout
timeout8 timeout16 timeout32 timeout64
*
.dSYM
bench
*
.so
*
.o
$(RM)
-r
timeout
timeout8 timeout16 timeout32 timeout64
*
.dSYM
*
.so
*
.o
clean~
:
clean
clean~
:
clean
$(RM)
*
~
$(RM)
*
~
bench-llrb.c
0 → 100644
View file @
a605dc78
/* ==========================================================================
* llrb.h - Iterative Left-leaning Red-Black Tree.
* --------------------------------------------------------------------------
* Copyright (c) 2011, 2013 William Ahern <william@25thandClement.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
* --------------------------------------------------------------------------
* CREDITS:
* o Algorithm courtesy of Robert Sedgewick, "Left-leaning Red-Black
* Trees" (September 2008); and Robert Sedgewick and Kevin Wayne,
* Algorithms (4th ed. 2011).
*
* Sedgewick touts the simplicity of the recursive implementation,
* but at least for the 2-3 tree variant the iterative approach is
* almost line-for-line identical. The magic of C pointers helps;
* it'd be uglier with Java.
*
* A couple of missing NULL checks were added to Sedgewick's deletion
* example, and insert was optimized to short-circuit rotations when
* walking up the tree.
*
* o Code implemented in the fashion of Niels Provos' excellent *BSD
* sys/tree.h pre-processor library.
*
* Regarding relative performance, I've refrained from sharing my own
* benchmarks. Differences in run-time speed were too correlated to
* compiler options and other external factors.
*
* Provos' delete implementation doesn't need to start at the root of
* the tree. However, RB_REMOVE must be passed the actual node to be
* removed. LLRB_REMOVE merely requires a key, much like
* RB_FIND/LLRB_FIND.
* ==========================================================================
*/
#ifndef LLRB_H
#define LLRB_H
#define LLRB_VENDOR "william@25thandClement.com"
#define LLRB_VERSION 0x20130925
#ifndef LLRB_STATIC
#ifdef __GNUC__
#define LLRB_STATIC __attribute__((__unused__)) static
#else
#define LLRB_STATIC static
#endif
#endif
#define LLRB_HEAD(name, type) \
struct name { struct type *rbh_root; }
#define LLRB_INITIALIZER(root) { 0 }
#define LLRB_INIT(root) do { (root)->rbh_root = 0; } while (0)
#define LLRB_BLACK 0
#define LLRB_RED 1
#define LLRB_ENTRY(type) \
struct { struct type *rbe_left, *rbe_right, *rbe_parent; _Bool rbe_color; }
#define LLRB_LEFT(elm, field) (elm)->field.rbe_left
#define LLRB_RIGHT(elm, field) (elm)->field.rbe_right
#define LLRB_PARENT(elm, field) (elm)->field.rbe_parent
#define LLRB_EDGE(head, elm, field) (((elm) == LLRB_ROOT(head))? &LLRB_ROOT(head) : ((elm) == LLRB_LEFT(LLRB_PARENT((elm), field), field))? &LLRB_LEFT(LLRB_PARENT((elm), field), field) : &LLRB_RIGHT(LLRB_PARENT((elm), field), field))
#define LLRB_COLOR(elm, field) (elm)->field.rbe_color
#define LLRB_ROOT(head) (head)->rbh_root
#define LLRB_EMPTY(head) ((head)->rbh_root == 0)
#define LLRB_ISRED(elm, field) ((elm) && LLRB_COLOR((elm), field) == LLRB_RED)
#define LLRB_PROTOTYPE(name, type, field, cmp) \
LLRB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
#define LLRB_PROTOTYPE_STATIC(name, type, field, cmp) \
LLRB_PROTOTYPE_INTERNAL(name, type, field, cmp, LLRB_STATIC)
#define LLRB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
attr struct type *name##_LLRB_INSERT(struct name *, struct type *); \
attr struct type *name##_LLRB_DELETE(struct name *, struct type *); \
attr struct type *name##_LLRB_FIND(struct name *, struct type *); \
attr struct type *name##_LLRB_MIN(struct type *); \
attr struct type *name##_LLRB_MAX(struct type *); \
attr struct type *name##_LLRB_NEXT(struct type *);
#define LLRB_GENERATE(name, type, field, cmp) \
LLRB_GENERATE_INTERNAL(name, type, field, cmp,)
#define LLRB_GENERATE_STATIC(name, type, field, cmp) \
LLRB_GENERATE_INTERNAL(name, type, field, cmp, LLRB_STATIC)
#define LLRB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
static inline void name##_LLRB_ROTL(struct type **pivot) { \
struct type *a = *pivot; \
struct type *b = LLRB_RIGHT(a, field); \
if ((LLRB_RIGHT(a, field) = LLRB_LEFT(b, field))) \
LLRB_PARENT(LLRB_RIGHT(a, field), field) = a; \
LLRB_LEFT(b, field) = a; \
LLRB_COLOR(b, field) = LLRB_COLOR(a, field); \
LLRB_COLOR(a, field) = LLRB_RED; \
LLRB_PARENT(b, field) = LLRB_PARENT(a, field); \
LLRB_PARENT(a, field) = b; \
*pivot = b; \
} \
static inline void name##_LLRB_ROTR(struct type **pivot) { \
struct type *b = *pivot; \
struct type *a = LLRB_LEFT(b, field); \
if ((LLRB_LEFT(b, field) = LLRB_RIGHT(a, field))) \
LLRB_PARENT(LLRB_LEFT(b, field), field) = b; \
LLRB_RIGHT(a, field) = b; \
LLRB_COLOR(a, field) = LLRB_COLOR(b, field); \
LLRB_COLOR(b, field) = LLRB_RED; \
LLRB_PARENT(a, field) = LLRB_PARENT(b, field); \
LLRB_PARENT(b, field) = a; \
*pivot = a; \
} \
static inline void name##_LLRB_FLIP(struct type *root) { \
LLRB_COLOR(root, field) = !LLRB_COLOR(root, field); \
LLRB_COLOR(LLRB_LEFT(root, field), field) = !LLRB_COLOR(LLRB_LEFT(root, field), field); \
LLRB_COLOR(LLRB_RIGHT(root, field), field) = !LLRB_COLOR(LLRB_RIGHT(root, field), field); \
} \
static inline void name##_LLRB_FIXUP(struct type **root) { \
if (LLRB_ISRED(LLRB_RIGHT(*root, field), field) && !LLRB_ISRED(LLRB_LEFT(*root, field), field)) \
name##_LLRB_ROTL(root); \
if (LLRB_ISRED(LLRB_LEFT(*root, field), field) && LLRB_ISRED(LLRB_LEFT(LLRB_LEFT(*root, field), field), field)) \
name##_LLRB_ROTR(root); \
if (LLRB_ISRED(LLRB_LEFT(*root, field), field) && LLRB_ISRED(LLRB_RIGHT(*root, field), field)) \
name##_LLRB_FLIP(*root); \
} \
attr struct type *name##_LLRB_INSERT(struct name *head, struct type *elm) { \
struct type **root = &LLRB_ROOT(head); \
struct type *parent = 0; \
while (*root) { \
int comp = (cmp)((elm), (*root)); \
parent = *root; \
if (comp < 0) \
root = &LLRB_LEFT(*root, field); \
else if (comp > 0) \
root = &LLRB_RIGHT(*root, field); \
else \
return *root; \
} \
LLRB_LEFT((elm), field) = 0; \
LLRB_RIGHT((elm), field) = 0; \
LLRB_COLOR((elm), field) = LLRB_RED; \
LLRB_PARENT((elm), field) = parent; \
*root = (elm); \
while (parent && (LLRB_ISRED(LLRB_LEFT(parent, field), field) || LLRB_ISRED(LLRB_RIGHT(parent, field), field))) { \
root = LLRB_EDGE(head, parent, field); \
parent = LLRB_PARENT(parent, field); \
name##_LLRB_FIXUP(root); \
} \
LLRB_COLOR(LLRB_ROOT(head), field) = LLRB_BLACK; \
return 0; \
} \
static inline void name##_LLRB_MOVL(struct type **pivot) { \
name##_LLRB_FLIP(*pivot); \
if (LLRB_ISRED(LLRB_LEFT(LLRB_RIGHT(*pivot, field), field), field)) { \
name##_LLRB_ROTR(&LLRB_RIGHT(*pivot, field)); \
name##_LLRB_ROTL(pivot); \
name##_LLRB_FLIP(*pivot); \
} \
} \
static inline void name##_LLRB_MOVR(struct type **pivot) { \
name##_LLRB_FLIP(*pivot); \
if (LLRB_ISRED(LLRB_LEFT(LLRB_LEFT(*pivot, field), field), field)) { \
name##_LLRB_ROTR(pivot); \
name##_LLRB_FLIP(*pivot); \
} \
} \
static inline struct type *name##_DELETEMIN(struct name *head, struct type **root) { \
struct type **pivot = root, *deleted, *parent; \
while (LLRB_LEFT(*pivot, field)) { \
if (!LLRB_ISRED(LLRB_LEFT(*pivot, field), field) && !LLRB_ISRED(LLRB_LEFT(LLRB_LEFT(*pivot, field), field), field)) \
name##_LLRB_MOVL(pivot); \
pivot = &LLRB_LEFT(*pivot, field); \
} \
deleted = *pivot; \
parent = LLRB_PARENT(*pivot, field); \
*pivot = 0; \
while (root != pivot) { \
pivot = LLRB_EDGE(head, parent, field); \
parent = LLRB_PARENT(parent, field); \
name##_LLRB_FIXUP(pivot); \
} \
return deleted; \
} \
attr struct type *name##_LLRB_DELETE(struct name *head, struct type *elm) { \
struct type **root = &LLRB_ROOT(head), *parent = 0, *deleted = 0; \
int comp; \
while (*root) { \
parent = LLRB_PARENT(*root, field); \
comp = (cmp)(elm, *root); \
if (comp < 0) { \
if (LLRB_LEFT(*root, field) && !LLRB_ISRED(LLRB_LEFT(*root, field), field) && !LLRB_ISRED(LLRB_LEFT(LLRB_LEFT(*root, field), field), field)) \
name##_LLRB_MOVL(root); \
root = &LLRB_LEFT(*root, field); \
} else { \
if (LLRB_ISRED(LLRB_LEFT(*root, field), field)) { \
name##_LLRB_ROTR(root); \
comp = (cmp)(elm, *root); \
} \
if (!comp && !LLRB_RIGHT(*root, field)) { \
deleted = *root; \
*root = 0; \
break; \
} \
if (LLRB_RIGHT(*root, field) && !LLRB_ISRED(LLRB_RIGHT(*root, field), field) && !LLRB_ISRED(LLRB_LEFT(LLRB_RIGHT(*root, field), field), field)) { \
name##_LLRB_MOVR(root); \
comp = (cmp)(elm, *root); \
} \
if (!comp) { \
struct type *orphan = name##_DELETEMIN(head, &LLRB_RIGHT(*root, field)); \
LLRB_COLOR(orphan, field) = LLRB_COLOR(*root, field); \
LLRB_PARENT(orphan, field) = LLRB_PARENT(*root, field); \
if ((LLRB_RIGHT(orphan, field) = LLRB_RIGHT(*root, field))) \
LLRB_PARENT(LLRB_RIGHT(orphan, field), field) = orphan; \
if ((LLRB_LEFT(orphan, field) = LLRB_LEFT(*root, field))) \
LLRB_PARENT(LLRB_LEFT(orphan, field), field) = orphan; \
deleted = *root; \
*root = orphan; \
parent = *root; \
break; \
} else \
root = &LLRB_RIGHT(*root, field); \
} \
} \
while (parent) { \
root = LLRB_EDGE(head, parent, field); \
parent = LLRB_PARENT(parent, field); \
name##_LLRB_FIXUP(root); \
} \
if (LLRB_ROOT(head)) \
LLRB_COLOR(LLRB_ROOT(head), field) = LLRB_BLACK; \
return deleted; \
} \
attr struct type *name##_LLRB_FIND(struct name *head, struct type *key) { \
struct type *elm = LLRB_ROOT(head); \
while (elm) { \
int comp = (cmp)(key, elm); \
if (comp < 0) \
elm = LLRB_LEFT(elm, field); \
else if (comp > 0) \
elm = LLRB_RIGHT(elm, field); \
else \
return elm; \
} \
return 0; \
} \
attr struct type *name##_LLRB_MIN(struct type *elm) { \
while (elm && LLRB_LEFT(elm, field)) \
elm = LLRB_LEFT(elm, field); \
return elm; \
} \
attr struct type *name##_LLRB_MAX(struct type *elm) { \
while (elm && LLRB_RIGHT(elm, field)) \
elm = LLRB_RIGHT(elm, field); \
return elm; \
} \
attr struct type *name##_LLRB_NEXT(struct type *elm) { \
if (LLRB_RIGHT(elm, field)) { \
return name##_LLRB_MIN(LLRB_RIGHT(elm, field)); \
} else if (LLRB_PARENT(elm, field)) { \
if (elm == LLRB_LEFT(LLRB_PARENT(elm, field), field)) \
return LLRB_PARENT(elm, field); \
while (LLRB_PARENT(elm, field) && elm == LLRB_RIGHT(LLRB_PARENT(elm, field), field)) \
elm = LLRB_PARENT(elm, field); \
return LLRB_PARENT(elm, field); \
} else return 0; \
}
#define LLRB_INSERT(name, head, elm) name##_LLRB_INSERT((head), (elm))
#define LLRB_DELETE(name, head, elm) name##_LLRB_DELETE((head), (elm))
#define LLRB_REMOVE(name, head, elm) name##_LLRB_DELETE((head), (elm))
#define LLRB_FIND(name, head, elm) name##_LLRB_FIND((head), (elm))
#define LLRB_MIN(name, head) name##_LLRB_MIN(LLRB_ROOT((head)))
#define LLRB_MAX(name, head) name##_LLRB_MAX(LLRB_ROOT((head)))
#define LLRB_NEXT(name, head, elm) name##_LLRB_NEXT((elm))
#define LLRB_FOREACH(elm, name, head) \
for ((elm) = LLRB_MIN(name, head); (elm); (elm) = name##_LLRB_NEXT((elm)))
#endif
/* LLRB_H */
#include <stdlib.h>
#include "timeout.h"
#include "bench.h"
struct
rbtimeout
{
timeout_t
expires
;
int
pending
;
LLRB_ENTRY
(
rbtimeout
)
rbe
;
};
struct
rbtimeouts
{
timeout_t
curtime
;
LLRB_HEAD
(
tree
,
rbtimeout
)
tree
;
};
static
int
timeoutcmp
(
struct
rbtimeout
*
a
,
struct
rbtimeout
*
b
)
{
if
(
a
->
expires
<
b
->
expires
)
return
-
1
;
else
if
(
a
->
expires
>
b
->
expires
)
return
1
;
else
if
(
a
<
b
)
return
-
1
;
else
if
(
a
>
b
)
return
1
;
else
return
0
;
}
/* timeoutcmp() */
LLRB_GENERATE_STATIC
(
tree
,
rbtimeout
,
rbe
,
timeoutcmp
)
static
void
*
init
(
struct
timeout
*
timeout
,
size_t
count
,
int
verbose
)
{
struct
rbtimeouts
*
T
;
size_t
i
;
T
=
malloc
(
sizeof
*
T
);
LLRB_INIT
(
&
T
->
tree
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
struct
rbtimeout
*
to
=
(
void
*
)
&
timeout
[
i
];
to
->
expires
=
0
;
to
->
pending
=
0
;
}
return
T
;
}
/* init() */
static
void
add
(
void
*
ctx
,
struct
timeout
*
_to
,
timeout_t
expires
)
{
struct
rbtimeouts
*
T
=
ctx
;
struct
rbtimeout
*
to
=
(
void
*
)
_to
;
to
->
expires
=
T
->
curtime
+
expires
;
LLRB_INSERT
(
tree
,
&
T
->
tree
,
to
);
to
->
pending
=
0
;
}
/* add() */
static
void
del
(
void
*
ctx
,
struct
timeout
*
_to
)
{
struct
rbtimeouts
*
T
=
ctx
;
struct
rbtimeout
*
to
=
(
void
*
)
_to
;
LLRB_REMOVE
(
tree
,
&
T
->
tree
,
to
);
to
->
pending
=
0
;
}
/* del() */
static
struct
timeout
*
get
(
void
*
ctx
)
{
struct
rbtimeouts
*
T
=
ctx
;
struct
rbtimeout
*
to
;
if
((
to
=
LLRB_MIN
(
tree
,
&
T
->
tree
))
&&
to
->
expires
<=
T
->
curtime
)
{
LLRB_REMOVE
(
tree
,
&
T
->
tree
,
to
);
to
->
pending
=
0
;
return
(
void
*
)
to
;
}
return
NULL
;
}
/* get() */
static
void
update
(
void
*
ctx
,
timeout_t
ts
)
{
struct
rbtimeouts
*
T
=
ctx
;
T
->
curtime
=
ts
;
}
/* update() */
static
void
check
(
void
*
ctx
)
{
return
;
}
/* check() */
static
int
empty
(
void
*
ctx
)
{
struct
rbtimeouts
*
T
=
ctx
;
return
LLRB_EMPTY
(
&
T
->
tree
);
}
/* empty() */
static
void
destroy
(
void
*
ctx
)
{
free
(
ctx
);
return
;
}
/* destroy() */
const
struct
benchops
benchops
=
{
.
init
=
&
init
,
.
add
=
&
add
,
.
del
=
&
del
,
.
get
=
&
get
,
.
update
=
&
update
,
.
check
=
&
check
,
.
empty
=
&
empty
,
.
destroy
=
&
destroy
,
};
bench.c
View file @
a605dc78
...
@@ -27,6 +27,13 @@ struct bench {
...
@@ -27,6 +27,13 @@ struct bench {
};
/* struct bench */
};
/* struct bench */
static
int
bench_clock
(
lua_State
*
L
)
{
lua_pushnumber
(
L
,
(
double
)
clock
()
/
CLOCKS_PER_SEC
);
return
1
;
}
/* bench_clock() */
static
int
bench_new
(
lua_State
*
L
)
{
static
int
bench_new
(
lua_State
*
L
)
{
const
char
*
path
=
luaL_checkstring
(
L
,
1
);
const
char
*
path
=
luaL_checkstring
(
L
,
1
);
size_t
count
=
luaL_optlong
(
L
,
2
,
1000000
);
size_t
count
=
luaL_optlong
(
L
,
2
,
1000000
);
...
@@ -89,9 +96,10 @@ static int bench_del(lua_State *L) {
...
@@ -89,9 +96,10 @@ static int bench_del(lua_State *L) {
static
int
bench_fill
(
lua_State
*
L
)
{
static
int
bench_fill
(
lua_State
*
L
)
{
struct
bench
*
B
=
lua_touserdata
(
L
,
1
);
struct
bench
*
B
=
lua_touserdata
(
L
,
1
);
size_t
count
=
luaL_optlong
(
L
,
2
,
B
->
count
);
size_t
i
;
size_t
i
;
for
(
i
=
0
;
i
<
B
->
count
;
i
++
)
{
for
(
i
=
0
;
i
<
count
;
i
++
)
{
B
->
ops
.
add
(
B
->
state
,
&
B
->
timeout
[
i
],
random
()
%
B
->
maximum
);
B
->
ops
.
add
(
B
->
state
,
&
B
->
timeout
[
i
],
random
()
%
B
->
maximum
);
}
}
...
@@ -134,6 +142,7 @@ static const luaL_Reg bench_methods[] = {
...
@@ -134,6 +142,7 @@ static const luaL_Reg bench_methods[] = {
{
"del"
,
&
bench_del
},
{
"del"
,
&
bench_del
},
{
"fill"
,
&
bench_fill
},
{
"fill"
,
&
bench_fill
},
{
"expire"
,
&
bench_expire
},
{
"expire"
,
&
bench_expire
},
{
"close"
,
&
bench__gc
},
{
NULL
,
NULL
}
{
NULL
,
NULL
}
};
};
...
@@ -143,7 +152,8 @@ static const luaL_Reg bench_metatable[] = {
...
@@ -143,7 +152,8 @@ static const luaL_Reg bench_metatable[] = {
};
};
static
const
luaL_Reg
bench_globals
[]
=
{
static
const
luaL_Reg
bench_globals
[]
=
{
{
"new"
,
&
bench_new
},
{
"new"
,
&
bench_new
},
{
"clock"
,
&
bench_clock
},
{
NULL
,
NULL
}
{
NULL
,
NULL
}
};
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment