iodine 0.2.7 → 0.2.8
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +5 -1
- data/ext/iodine/base64.c +3 -3
- data/ext/iodine/base64.h +3 -3
- data/ext/iodine/bscrypt-common.h +5 -5
- data/ext/iodine/bscrypt.h +4 -4
- data/ext/iodine/hex.c +11 -10
- data/ext/iodine/hex.h +3 -3
- data/ext/iodine/http.c +34 -27
- data/ext/iodine/http.h +15 -8
- data/ext/iodine/http1.c +63 -60
- data/ext/iodine/http1.h +10 -5
- data/ext/iodine/http1_simple_parser.c +6 -0
- data/ext/iodine/http1_simple_parser.h +10 -6
- data/ext/iodine/http_request.h +28 -22
- data/ext/iodine/http_response.c +22 -7
- data/ext/iodine/http_response.h +6 -0
- data/ext/iodine/http_response_http1.h +9 -1
- data/ext/iodine/iodine_core.c +6 -1
- data/ext/iodine/iodine_core.h +13 -6
- data/ext/iodine/iodine_http.c +6 -0
- data/ext/iodine/iodine_http.h +6 -0
- data/ext/iodine/iodine_websocket.c +23 -4
- data/ext/iodine/iodine_websocket.h +2 -2
- data/ext/iodine/libasync.c +5 -3
- data/ext/iodine/libasync.h +8 -8
- data/ext/iodine/libreact.c +8 -8
- data/ext/iodine/libreact.h +5 -5
- data/ext/iodine/libserver.c +2 -2
- data/ext/iodine/libserver.h +2 -2
- data/ext/iodine/libsock.c +2 -2
- data/ext/iodine/libsock.h +3 -3
- data/ext/iodine/mempool.h +826 -0
- data/ext/iodine/misc.c +14 -14
- data/ext/iodine/misc.h +3 -3
- data/ext/iodine/random.c +6 -6
- data/ext/iodine/random.h +3 -3
- data/ext/iodine/rb-call.c +6 -0
- data/ext/iodine/rb-call.h +2 -2
- data/ext/iodine/rb-libasync.h +5 -3
- data/ext/iodine/rb-rack-io.c +15 -3
- data/ext/iodine/rb-rack-io.h +5 -2
- data/ext/iodine/rb-registry.c +6 -0
- data/ext/iodine/rb-registry.h +2 -2
- data/ext/iodine/sha1.c +13 -11
- data/ext/iodine/sha1.h +3 -3
- data/ext/iodine/sha2.c +8 -6
- data/ext/iodine/sha2.h +3 -3
- data/ext/iodine/siphash.c +9 -2
- data/ext/iodine/siphash.h +8 -1
- data/ext/iodine/spnlock.h +9 -3
- data/ext/iodine/websockets.c +62 -38
- data/ext/iodine/websockets.h +6 -0
- data/ext/iodine/xor-crypt.c +3 -3
- data/ext/iodine/xor-crypt.h +3 -3
- data/lib/iodine/version.rb +1 -1
- metadata +3 -4
- data/ext/iodine/rb-call.c_old +0 -127
- data/ext/iodine/rb-registry_old.c_old +0 -213
data/ext/iodine/libasync.c
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
/*
|
2
|
-
copyright: Boaz segev, 2016
|
2
|
+
copyright: Boaz segev, 2016-2017
|
3
3
|
license: MIT
|
4
4
|
|
5
5
|
Feel free to copy, use and enjoy according to the license provided.
|
6
6
|
*/
|
7
|
+
// clang-format off
|
7
8
|
#include "rb-libasync.h"
|
9
|
+
// clang-format on
|
8
10
|
#ifndef _GNU_SOURCE
|
9
11
|
#define _GNU_SOURCE
|
10
12
|
#endif
|
@@ -43,7 +45,7 @@ Performance options.
|
|
43
45
|
|
44
46
|
/* Sentinal thread to respawn crashed threads - limited crash resistance. */
|
45
47
|
#ifndef ASYNC_USE_SENTINEL
|
46
|
-
#define ASYNC_USE_SENTINEL
|
48
|
+
#define ASYNC_USE_SENTINEL 0
|
47
49
|
#endif
|
48
50
|
|
49
51
|
/* *****************************************************************************
|
@@ -241,7 +243,7 @@ static inline void perform_tasks(void) {
|
|
241
243
|
}
|
242
244
|
|
243
245
|
/******************************************************************************
|
244
|
-
|
246
|
+
Pausing and resuming threads
|
245
247
|
*/
|
246
248
|
|
247
249
|
static inline void pause_thread() {
|
data/ext/iodine/libasync.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
|
2
|
+
Copyright: Boaz segev, 2016-2017
|
3
|
+
License: MIT
|
4
4
|
|
5
5
|
Feel free to copy, use and enjoy according to the license provided.
|
6
6
|
*/
|
@@ -10,8 +10,8 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
10
10
|
#define LIB_ASYNC_VERSION_MINOR 4
|
11
11
|
#define LIB_ASYNC_VERSION_PATCH 0
|
12
12
|
|
13
|
-
#include <stdlib.h>
|
14
13
|
#include <stdio.h>
|
14
|
+
#include <stdlib.h>
|
15
15
|
|
16
16
|
#ifdef DEBUG
|
17
17
|
// prints out testing and benchmarking data
|
@@ -101,17 +101,17 @@ Use:
|
|
101
101
|
async_run(task, arg);
|
102
102
|
|
103
103
|
*/
|
104
|
-
int async_run(void (*task)(void*), void*
|
104
|
+
int async_run(void (*task)(void *), void *arg);
|
105
105
|
|
106
106
|
/**
|
107
107
|
Same as:
|
108
108
|
|
109
109
|
`async_signal(); async_wait();`
|
110
110
|
*/
|
111
|
-
#define async_finish()
|
112
|
-
{
|
113
|
-
async_signal();
|
114
|
-
async_join();
|
111
|
+
#define async_finish() \
|
112
|
+
{ \
|
113
|
+
async_signal(); \
|
114
|
+
async_join(); \
|
115
115
|
}
|
116
116
|
|
117
117
|
#endif /* LIB_ASYNC */
|
data/ext/iodine/libreact.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
|
2
|
+
Copyright: Boaz segev, 2016-2017
|
3
|
+
License: MIT
|
4
4
|
|
5
5
|
Feel free to copy, use and enjoy according to the license provided.
|
6
6
|
*/
|
@@ -9,20 +9,20 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
9
9
|
#if !defined(__linux__) && !defined(__CYGWIN__)
|
10
10
|
#include <sys/event.h>
|
11
11
|
#else
|
12
|
-
#include <sys/timerfd.h>
|
13
12
|
#include <sys/epoll.h>
|
13
|
+
#include <sys/timerfd.h>
|
14
14
|
#endif
|
15
|
-
#include <time.h>
|
16
15
|
#include <assert.h>
|
17
|
-
#include <unistd.h>
|
18
|
-
#include <fcntl.h>
|
19
16
|
#include <errno.h>
|
17
|
+
#include <fcntl.h>
|
18
|
+
#include <netdb.h>
|
20
19
|
#include <stdio.h>
|
21
20
|
#include <stdlib.h>
|
22
21
|
#include <string.h>
|
23
|
-
#include <netdb.h>
|
24
|
-
#include <sys/types.h>
|
25
22
|
#include <sys/socket.h>
|
23
|
+
#include <sys/types.h>
|
24
|
+
#include <time.h>
|
25
|
+
#include <unistd.h>
|
26
26
|
|
27
27
|
/* The (sadly, global) reactor fd */
|
28
28
|
static int reactor_fd = -1;
|
data/ext/iodine/libreact.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
|
2
|
+
Copyright: Boaz segev, 2016-2017
|
3
|
+
License: MIT
|
4
4
|
|
5
5
|
Feel free to copy, use and enjoy according to the license provided.
|
6
6
|
*/
|
@@ -22,11 +22,11 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
22
22
|
#endif
|
23
23
|
|
24
24
|
#include <stdint.h>
|
25
|
-
#include <unistd.h>
|
26
25
|
#include <sys/time.h>
|
27
26
|
#include <sys/types.h>
|
27
|
+
#include <unistd.h>
|
28
28
|
|
29
|
-
#if !defined(__unix__) && !defined(__linux__) && !defined(__APPLE__) &&
|
29
|
+
#if !defined(__unix__) && !defined(__linux__) && !defined(__APPLE__) && \
|
30
30
|
!defined(__CYGWIN__)
|
31
31
|
#error This library currently supports only Unix based systems (i.e. Linux and BSD)
|
32
32
|
#endif
|
@@ -83,8 +83,8 @@ Here are the supported events and their callbacks:
|
|
83
83
|
|
84
84
|
Here's a quick example for an HTTP hello world (no HTTP parsing required)...:
|
85
85
|
|
86
|
-
#include "libsock.h" // easy socket functions, also allows integration.
|
87
86
|
#include "libreact.h" // the reactor library
|
87
|
+
#include "libsock.h" // easy socket functions, also allows integration.
|
88
88
|
|
89
89
|
// a global server socket
|
90
90
|
int srvfd = -1;
|
data/ext/iodine/libserver.c
CHANGED
data/ext/iodine/libserver.h
CHANGED
data/ext/iodine/libsock.c
CHANGED
data/ext/iodine/libsock.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
|
-
|
3
|
-
|
2
|
+
Copyright: Boaz segev, 2016-2017
|
3
|
+
License: MIT
|
4
4
|
|
5
5
|
Feel free to copy, use and enjoy according to the license provided.
|
6
6
|
*/
|
@@ -20,10 +20,10 @@ The library is designed to be thread safe, but not fork safe.
|
|
20
20
|
*/
|
21
21
|
|
22
22
|
#include <stdint.h>
|
23
|
-
#include <unistd.h>
|
24
23
|
#include <stdio.h>
|
25
24
|
#include <stdlib.h>
|
26
25
|
#include <sys/types.h>
|
26
|
+
#include <unistd.h>
|
27
27
|
|
28
28
|
#ifndef __unused
|
29
29
|
#define __unused __attribute__((unused))
|
@@ -0,0 +1,826 @@
|
|
1
|
+
/*
|
2
|
+
Copyright: Boaz segev, 2016-2017
|
3
|
+
License: MIT
|
4
|
+
|
5
|
+
Feel free to copy, use and enjoy according to the license provided.
|
6
|
+
*/
|
7
|
+
#ifndef MEMPOOL_H
|
8
|
+
|
9
|
+
/* *****************************************************************************
|
10
|
+
A simple `mmap` based localized memory pool (localized `malloc` alternative).
|
11
|
+
|
12
|
+
The memory pool is localized to the same object file (C file). See NOTICE.
|
13
|
+
|
14
|
+
The issue: objects that have a long life, such as Websocket / HTTP2 protocol
|
15
|
+
objects or server wide strings with reference counts, cause memory fragmentation
|
16
|
+
when allocated on the heap alongside objects that have a short life.
|
17
|
+
|
18
|
+
This is a common issue when using `malloc` in long running processes for all
|
19
|
+
allocations.
|
20
|
+
|
21
|
+
This issue effects long running processes (such as servers) while it's effect on
|
22
|
+
short lived proccesses are less accute and could often be ignored.
|
23
|
+
|
24
|
+
To circumvent this issue, a seperate memory allocation method is used for
|
25
|
+
long-lived objects.
|
26
|
+
|
27
|
+
This memory pool allocates large blocks of memory (~2Mb at a time), minimizing
|
28
|
+
small memory fragmentation by both reserving large memory blocks and seperating
|
29
|
+
memory locality between long lived objects and short lived objects.
|
30
|
+
|
31
|
+
The memory pool isn't expected to be faster than the system's `malloc`
|
32
|
+
(although, sometimes it might perform better). However, selective use of this
|
33
|
+
memory pool could improve concurrency (each pool has a seperate lock, unlike
|
34
|
+
`malloc`'s system lock') as well as help with memory fragmentation.
|
35
|
+
|
36
|
+
================================================================================
|
37
|
+
NOTICE:
|
38
|
+
|
39
|
+
The memory pool is attached to the specific file. in which `mempool.h` is
|
40
|
+
included.
|
41
|
+
|
42
|
+
The memory shoule NEVER be freed from a different file.
|
43
|
+
|
44
|
+
However, it's easy to work around this limitation by wrapping the `mempool_`
|
45
|
+
functions using proper `create` / `destroy` functions for any objects.
|
46
|
+
|
47
|
+
================================================================================
|
48
|
+
|
49
|
+
This file requires the "spnlock.h" library file as well. Together these files
|
50
|
+
can be used also seperately from the `facil.io` library.
|
51
|
+
|
52
|
+
*/
|
53
|
+
#define MEMPOOL_H
|
54
|
+
MEMPOOL_H
|
55
|
+
#ifndef _GNU_SOURCE
|
56
|
+
#define _GNU_SOURCE
|
57
|
+
#endif
|
58
|
+
|
59
|
+
#include <errno.h>
|
60
|
+
#include <signal.h>
|
61
|
+
#include <stdint.h>
|
62
|
+
#include <stdio.h>
|
63
|
+
#include <stdlib.h>
|
64
|
+
#include <string.h>
|
65
|
+
|
66
|
+
#ifndef __unused
|
67
|
+
#define __unused __attribute__((unused))
|
68
|
+
#endif
|
69
|
+
|
70
|
+
/* *****************************************************************************
|
71
|
+
********************************************************************************
|
72
|
+
API Declerations
|
73
|
+
********************************************************************************
|
74
|
+
***************************************************************************** */
|
75
|
+
|
76
|
+
/** Allocates memory from the pool. */
|
77
|
+
static __unused void *mempool_malloc(size_t size);
|
78
|
+
/**
|
79
|
+
* Frees the memory, releasing it back to the pool (or, sometimes, the system).
|
80
|
+
*/
|
81
|
+
static __unused void mempool_free(void *ptr);
|
82
|
+
/**
|
83
|
+
* Behaves the same a the systems `realloc`, attempting to resize the memory
|
84
|
+
* when possible.
|
85
|
+
*
|
86
|
+
* On error returns NULL (the old pointer data remains allocated and valid)
|
87
|
+
* otherwise returns a new pointer (either equal to the old or after
|
88
|
+
* deallocating the old one).
|
89
|
+
*/
|
90
|
+
static __unused void *mempool_realloc(void *ptr, size_t new_size);
|
91
|
+
|
92
|
+
#if defined(DEBUG) && DEBUG == 1
|
93
|
+
/** Tests the memory pool, both testing against issues / corruption and testing
|
94
|
+
* it's performance against the system's `malloc`.
|
95
|
+
*/
|
96
|
+
static __unused void mempool_test(void);
|
97
|
+
#endif
|
98
|
+
|
99
|
+
/* *****************************************************************************
|
100
|
+
********************************************************************************
|
101
|
+
Implementation
|
102
|
+
********************************************************************************
|
103
|
+
***************************************************************************** */
|
104
|
+
|
105
|
+
/* *****************************************************************************
|
106
|
+
Memory block allocation
|
107
|
+
*/
|
108
|
+
|
109
|
+
#define MEMPOOL_BLOCK_SIZE (1UL << 21)
|
110
|
+
#define MEMPOOL_ORDERING_LIMIT 32
|
111
|
+
#define MEMPOOL_RETURN_MEM_TO_SYSTEM 1
|
112
|
+
|
113
|
+
/* Will we use mmap or malloc? */
|
114
|
+
// clang-format off
|
115
|
+
#ifdef __has_include
|
116
|
+
/* check for unix support */
|
117
|
+
# if __has_include(<unistd.h>) && __has_include(<sys/mman.h>)
|
118
|
+
# define HAS_UNIX_FEATURES
|
119
|
+
# endif
|
120
|
+
#endif
|
121
|
+
// clang-format on
|
122
|
+
|
123
|
+
#ifdef HAS_UNIX_FEATURES
|
124
|
+
#include <sys/mman.h>
|
125
|
+
#include <unistd.h>
|
126
|
+
|
127
|
+
/* *****************************************************************************
|
128
|
+
spnlock.h (can also be embeded instead of included)
|
129
|
+
*/
|
130
|
+
#include "spnlock.h"
|
131
|
+
|
132
|
+
/* *****************************************************************************
|
133
|
+
Memory slices, tree and helpers
|
134
|
+
*/
|
135
|
+
|
136
|
+
typedef struct mempool_reserved_slice_s {
|
137
|
+
struct mempool_reserved_slice_s_offset { /** offset from this slice */
|
138
|
+
uint32_t reserved1; /* used to make the offset 16 bytes long */
|
139
|
+
uint32_t ahead;
|
140
|
+
uint32_t behind;
|
141
|
+
uint32_t reserved2; /* used to make the offset 16 bytes long */
|
142
|
+
} offset;
|
143
|
+
/** Used for the free slices linked list. */
|
144
|
+
struct mempool_reserved_slice_s *next;
|
145
|
+
struct mempool_reserved_slice_s *prev;
|
146
|
+
} mempool_reserved_slice_s;
|
147
|
+
|
148
|
+
static struct {
|
149
|
+
mempool_reserved_slice_s *available;
|
150
|
+
spn_lock_i lock;
|
151
|
+
} mempool_reserved_pool = {.available = NULL, .lock = SPN_LOCK_INIT};
|
152
|
+
|
153
|
+
#define MEMPOOL_LOCK() spn_lock(&mempool_reserved_pool.lock)
|
154
|
+
#define MEMPOOL_UNLOCK() spn_unlock(&mempool_reserved_pool.lock)
|
155
|
+
|
156
|
+
#define MEMPOOL_USED_MARKER ((uint32_t)(~0UL << 21))
|
157
|
+
#define MEMPOOL_INDI_MARKER ((uint32_t)0xF7F7F7F7UL)
|
158
|
+
#define MEMPOOL_SIZE_MASK (MEMPOOL_BLOCK_SIZE - 1)
|
159
|
+
|
160
|
+
#define MEMPOOL_SLICE2PTR(slice) \
|
161
|
+
((void *)(((uintptr_t)(slice)) + \
|
162
|
+
(sizeof(struct mempool_reserved_slice_s_offset))))
|
163
|
+
#define MEMPOOL_PTR2SLICE(ptr) \
|
164
|
+
((mempool_reserved_slice_s *)(((uintptr_t)(ptr)) - \
|
165
|
+
(sizeof( \
|
166
|
+
struct mempool_reserved_slice_s_offset))))
|
167
|
+
|
168
|
+
/* *****************************************************************************
|
169
|
+
Memory Block Allocation / Deallocation
|
170
|
+
*/
|
171
|
+
|
172
|
+
#define MEMPOOL_ALLOC_SPECIAL(target, size) \
|
173
|
+
do { \
|
174
|
+
target = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, \
|
175
|
+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); \
|
176
|
+
if (target == MAP_FAILED) \
|
177
|
+
target == NULL; \
|
178
|
+
} while (0);
|
179
|
+
|
180
|
+
#define MEMPOOL_DEALLOC_SPECIAL(target, size) munmap((target), (size))
|
181
|
+
|
182
|
+
#else
|
183
|
+
|
184
|
+
#define MEMPOOL_ALLOC_SPECIAL(target, size) \
|
185
|
+
do { \
|
186
|
+
target = malloc(size); \
|
187
|
+
} while (0);
|
188
|
+
|
189
|
+
#define MEMPOOL_DEALLOC_SPECIAL(target, size) free((target));
|
190
|
+
|
191
|
+
#endif
|
192
|
+
|
193
|
+
/* *****************************************************************************
|
194
|
+
Helpers: Memory block slicing and memory pool list maintanence.
|
195
|
+
*/
|
196
|
+
|
197
|
+
/* *****************************************************************************
|
198
|
+
API implementation
|
199
|
+
*/
|
200
|
+
|
201
|
+
static __unused void *mempool_malloc(size_t size) {
|
202
|
+
if (!size)
|
203
|
+
return NULL;
|
204
|
+
if (size & 15) {
|
205
|
+
size = (size & (~16)) + 16;
|
206
|
+
}
|
207
|
+
size += sizeof(struct mempool_reserved_slice_s_offset);
|
208
|
+
|
209
|
+
mempool_reserved_slice_s *slice = NULL;
|
210
|
+
|
211
|
+
if (size > (MEMPOOL_BLOCK_SIZE - (sizeof(mempool_reserved_slice_s) << 1)))
|
212
|
+
goto alloc_indi;
|
213
|
+
slice = mempool_reserved_pool.available;
|
214
|
+
MEMPOOL_LOCK();
|
215
|
+
while (slice && slice->offset.ahead < size)
|
216
|
+
slice = slice->next;
|
217
|
+
if (slice) {
|
218
|
+
/* remove slice from available memory list */
|
219
|
+
if (slice->next)
|
220
|
+
slice->next->prev = slice->prev;
|
221
|
+
if (slice->prev)
|
222
|
+
slice->prev->next = slice->next;
|
223
|
+
else
|
224
|
+
mempool_reserved_pool.available = slice->next;
|
225
|
+
slice->next = NULL;
|
226
|
+
slice->prev = NULL;
|
227
|
+
} else {
|
228
|
+
MEMPOOL_ALLOC_SPECIAL(slice, MEMPOOL_BLOCK_SIZE);
|
229
|
+
// fprintf(stderr, "Allocated Block at %p\n", slice);
|
230
|
+
slice->offset.behind = 0;
|
231
|
+
slice->offset.ahead =
|
232
|
+
MEMPOOL_BLOCK_SIZE - (sizeof(struct mempool_reserved_slice_s_offset));
|
233
|
+
|
234
|
+
mempool_reserved_slice_s *tmp =
|
235
|
+
(mempool_reserved_slice_s
|
236
|
+
*)(((uintptr_t)(slice)) + MEMPOOL_BLOCK_SIZE -
|
237
|
+
(sizeof(struct mempool_reserved_slice_s_offset)));
|
238
|
+
tmp->offset.ahead = 0;
|
239
|
+
tmp->offset.behind = slice->offset.ahead;
|
240
|
+
}
|
241
|
+
|
242
|
+
if (!slice) {
|
243
|
+
MEMPOOL_UNLOCK();
|
244
|
+
fprintf(stderr, "mempool: no memory\n");
|
245
|
+
return NULL;
|
246
|
+
}
|
247
|
+
|
248
|
+
if (slice->offset.ahead > (size + sizeof(mempool_reserved_slice_s))) {
|
249
|
+
/* cut the slice in two */
|
250
|
+
mempool_reserved_slice_s *tmp =
|
251
|
+
(mempool_reserved_slice_s *)(((uintptr_t)slice) + size);
|
252
|
+
tmp->offset.behind = size;
|
253
|
+
tmp->offset.ahead = slice->offset.ahead - size;
|
254
|
+
slice->offset.ahead = size;
|
255
|
+
/* inform higher neighbor about any updates */
|
256
|
+
((mempool_reserved_slice_s *)(((uintptr_t)tmp) + tmp->offset.ahead))
|
257
|
+
->offset.behind = tmp->offset.ahead;
|
258
|
+
/* place the new slice in the available memory list */
|
259
|
+
uint16_t limit = MEMPOOL_ORDERING_LIMIT;
|
260
|
+
tmp->next = NULL;
|
261
|
+
tmp->prev = NULL;
|
262
|
+
mempool_reserved_slice_s **pos = &mempool_reserved_pool.available;
|
263
|
+
while (limit && *pos && ((*pos)->offset.ahead < tmp->offset.ahead)) {
|
264
|
+
tmp->prev = *pos;
|
265
|
+
pos = &(*pos)->next;
|
266
|
+
--limit;
|
267
|
+
}
|
268
|
+
if (*pos) {
|
269
|
+
tmp->next = *pos;
|
270
|
+
tmp->next->prev = tmp;
|
271
|
+
*pos = tmp;
|
272
|
+
} else {
|
273
|
+
*pos = tmp;
|
274
|
+
}
|
275
|
+
}
|
276
|
+
|
277
|
+
slice->offset.ahead |= MEMPOOL_USED_MARKER;
|
278
|
+
MEMPOOL_UNLOCK();
|
279
|
+
slice->next = NULL;
|
280
|
+
slice->prev = NULL;
|
281
|
+
// mempool_reserved_slice_s *tmp =
|
282
|
+
// (void *)((uintptr_t)slice + (slice->offset.ahead &
|
283
|
+
// MEMPOOL_SIZE_MASK));
|
284
|
+
// fprintf(stderr, "Allocated %lu bytes at: %u <- %p -> %u."
|
285
|
+
// "next: %u <- %p -> %u\n ",
|
286
|
+
// size, slice->offset.behind, slice,
|
287
|
+
// (uint32_t)(slice->offset.ahead & MEMPOOL_SIZE_MASK),
|
288
|
+
// tmp->offset.behind, tmp,
|
289
|
+
// (uint32_t)(tmp->offset.ahead & MEMPOOL_SIZE_MASK));
|
290
|
+
return MEMPOOL_SLICE2PTR(slice);
|
291
|
+
alloc_indi:
|
292
|
+
MEMPOOL_ALLOC_SPECIAL(slice, size);
|
293
|
+
if (slice) {
|
294
|
+
slice->offset.ahead = size;
|
295
|
+
slice->offset.behind = MEMPOOL_INDI_MARKER;
|
296
|
+
}
|
297
|
+
return MEMPOOL_SLICE2PTR(slice);
|
298
|
+
}
|
299
|
+
|
300
|
+
/**
|
301
|
+
* Frees the memory, releasing it back to the pool (or, sometimes, the
|
302
|
+
* system).
|
303
|
+
*/
|
304
|
+
static __unused void mempool_free(void *ptr) {
|
305
|
+
if (!ptr)
|
306
|
+
return;
|
307
|
+
mempool_reserved_slice_s **pos, *slice = MEMPOOL_PTR2SLICE(ptr), *tmp;
|
308
|
+
|
309
|
+
if (slice->offset.behind == MEMPOOL_INDI_MARKER)
|
310
|
+
goto alloc_indi;
|
311
|
+
if ((slice->offset.ahead & MEMPOOL_USED_MARKER) != MEMPOOL_USED_MARKER)
|
312
|
+
goto error;
|
313
|
+
|
314
|
+
MEMPOOL_LOCK();
|
315
|
+
slice->offset.ahead &= MEMPOOL_SIZE_MASK;
|
316
|
+
/* merge slice with upper boundry */
|
317
|
+
while ((tmp = (mempool_reserved_slice_s *)(((uintptr_t)slice) +
|
318
|
+
slice->offset.ahead))
|
319
|
+
->offset.ahead &&
|
320
|
+
(tmp->offset.ahead & MEMPOOL_USED_MARKER) == 0) {
|
321
|
+
/* extract merged slice from list */
|
322
|
+
if (tmp->next)
|
323
|
+
tmp->next->prev = tmp->prev;
|
324
|
+
if (tmp->prev)
|
325
|
+
tmp->prev->next = tmp->next;
|
326
|
+
else
|
327
|
+
mempool_reserved_pool.available = tmp->next;
|
328
|
+
|
329
|
+
tmp->next = NULL;
|
330
|
+
tmp->prev = NULL;
|
331
|
+
slice->offset.ahead += tmp->offset.ahead;
|
332
|
+
}
|
333
|
+
/* merge slice with lower boundry */
|
334
|
+
while (slice->offset.behind &&
|
335
|
+
((tmp = (mempool_reserved_slice_s *)(((uintptr_t)slice) -
|
336
|
+
slice->offset.behind))
|
337
|
+
->offset.ahead &
|
338
|
+
MEMPOOL_USED_MARKER) == 0) {
|
339
|
+
/* extract merged slice from list */
|
340
|
+
if (tmp->next)
|
341
|
+
tmp->next->prev = tmp->prev;
|
342
|
+
if (tmp->prev)
|
343
|
+
tmp->prev->next = tmp->next;
|
344
|
+
else
|
345
|
+
mempool_reserved_pool.available = tmp->next;
|
346
|
+
|
347
|
+
tmp->next = NULL;
|
348
|
+
tmp->prev = NULL;
|
349
|
+
tmp->offset.ahead += slice->offset.ahead;
|
350
|
+
|
351
|
+
slice = tmp;
|
352
|
+
}
|
353
|
+
|
354
|
+
/* return memory to system, if the block is no longer required. */
|
355
|
+
if (MEMPOOL_RETURN_MEM_TO_SYSTEM && mempool_reserved_pool.available &&
|
356
|
+
slice->offset.behind == 0 &&
|
357
|
+
((mempool_reserved_slice_s *)(((uintptr_t)slice) + slice->offset.ahead))
|
358
|
+
->offset.ahead == 0) {
|
359
|
+
MEMPOOL_UNLOCK();
|
360
|
+
// fprintf(
|
361
|
+
// stderr, "DEALLOCATED BLOCK %p, size review %u == %lu %s\n", slice,
|
362
|
+
// slice->offset.ahead,
|
363
|
+
// MEMPOOL_BLOCK_SIZE - sizeof(struct mempool_reserved_slice_s_offset),
|
364
|
+
// (slice->offset.ahead ==
|
365
|
+
// MEMPOOL_BLOCK_SIZE - sizeof(struct mempool_reserved_slice_s_offset))
|
366
|
+
// ? "passed."
|
367
|
+
// : "FAILED.");
|
368
|
+
MEMPOOL_DEALLOC_SPECIAL(slice, MEMPOOL_BLOCK_SIZE);
|
369
|
+
return;
|
370
|
+
}
|
371
|
+
|
372
|
+
/* inform higher neighbor about any updates */
|
373
|
+
// fprintf(stderr, "slice: %p -> %u\n", slice, slice->offset.ahead);
|
374
|
+
((mempool_reserved_slice_s *)(((uintptr_t)slice) + slice->offset.ahead))
|
375
|
+
->offset.behind = slice->offset.ahead;
|
376
|
+
|
377
|
+
/* place slice in list */
|
378
|
+
uint8_t limit = MEMPOOL_ORDERING_LIMIT;
|
379
|
+
slice->next = NULL;
|
380
|
+
slice->prev = NULL;
|
381
|
+
pos = &mempool_reserved_pool.available;
|
382
|
+
while (limit && *pos && ((*pos)->offset.ahead < slice->offset.ahead)) {
|
383
|
+
slice->prev = *pos;
|
384
|
+
pos = &(*pos)->next;
|
385
|
+
--limit;
|
386
|
+
}
|
387
|
+
if (*pos) {
|
388
|
+
slice->next = *pos;
|
389
|
+
slice->next->prev = slice;
|
390
|
+
*pos = slice;
|
391
|
+
} else {
|
392
|
+
*pos = slice;
|
393
|
+
}
|
394
|
+
|
395
|
+
MEMPOOL_UNLOCK();
|
396
|
+
return;
|
397
|
+
alloc_indi:
|
398
|
+
MEMPOOL_DEALLOC_SPECIAL(slice, slice->offset.ahead);
|
399
|
+
return;
|
400
|
+
error:
|
401
|
+
MEMPOOL_UNLOCK();
|
402
|
+
if ((slice->offset.ahead & MEMPOOL_USED_MARKER) == 0)
|
403
|
+
fprintf(stderr, "mempool: memory being freed is already free.\n");
|
404
|
+
else
|
405
|
+
fprintf(stderr, "mempool: memory allocation data corrupted. possible "
|
406
|
+
"buffer overflow?\n");
|
407
|
+
errno = EFAULT;
|
408
|
+
raise(SIGSEGV); /* support longjmp rescue */
|
409
|
+
exit(EFAULT);
|
410
|
+
}
|
411
|
+
/**
|
412
|
+
* Behaves the same a the systems `realloc`, attempting to resize the memory
|
413
|
+
* when possible. On error returns NULL (the old pointer data remains allocated
|
414
|
+
* and valid) otherwise returns a new pointer (either equal to the old or after
|
415
|
+
* deallocating the old one).
|
416
|
+
*/
|
417
|
+
static __unused void *mempool_realloc(void *ptr, size_t size) {
|
418
|
+
if (!size)
|
419
|
+
return NULL;
|
420
|
+
if (size & 15) {
|
421
|
+
size = (size & (~16)) + 16;
|
422
|
+
}
|
423
|
+
size += sizeof(struct mempool_reserved_slice_s_offset);
|
424
|
+
|
425
|
+
mempool_reserved_slice_s *tmp = NULL, *slice = MEMPOOL_PTR2SLICE(ptr);
|
426
|
+
|
427
|
+
if (slice->offset.behind == MEMPOOL_INDI_MARKER)
|
428
|
+
goto realloc_indi;
|
429
|
+
if ((slice->offset.ahead & MEMPOOL_USED_MARKER) != MEMPOOL_USED_MARKER)
|
430
|
+
goto error;
|
431
|
+
|
432
|
+
slice->offset.ahead &= MEMPOOL_SIZE_MASK;
|
433
|
+
|
434
|
+
MEMPOOL_LOCK();
|
435
|
+
/* merge slice with upper boundry */
|
436
|
+
while ((tmp = (mempool_reserved_slice_s *)(((uintptr_t)slice) +
|
437
|
+
slice->offset.ahead))
|
438
|
+
->offset.ahead &&
|
439
|
+
(tmp->offset.ahead & MEMPOOL_USED_MARKER) == 0) {
|
440
|
+
/* extract merged slice from list */
|
441
|
+
if (tmp->next)
|
442
|
+
tmp->next->prev = tmp->prev;
|
443
|
+
if (tmp->prev)
|
444
|
+
tmp->prev->next = tmp->next;
|
445
|
+
else
|
446
|
+
mempool_reserved_pool.available = tmp->next;
|
447
|
+
|
448
|
+
tmp->next = NULL;
|
449
|
+
tmp->prev = NULL;
|
450
|
+
slice->offset.ahead += tmp->offset.ahead;
|
451
|
+
}
|
452
|
+
|
453
|
+
/* inform higher neighbor about any updates */
|
454
|
+
((mempool_reserved_slice_s *)(((uintptr_t)slice) + slice->offset.ahead))
|
455
|
+
->offset.behind = slice->offset.ahead;
|
456
|
+
|
457
|
+
if ((slice->offset.ahead) > size + sizeof(mempool_reserved_slice_s)) {
|
458
|
+
/* cut the slice in two */
|
459
|
+
tmp = (mempool_reserved_slice_s *)(((uintptr_t)slice) + size);
|
460
|
+
tmp->offset.behind = size;
|
461
|
+
tmp->offset.ahead = slice->offset.ahead - size;
|
462
|
+
slice->offset.ahead = size;
|
463
|
+
/* inform higher neighbor about any updates */
|
464
|
+
((mempool_reserved_slice_s *)(((uintptr_t)tmp) + tmp->offset.ahead))
|
465
|
+
->offset.behind = tmp->offset.ahead;
|
466
|
+
/* place the new slice in the available memory list */
|
467
|
+
tmp->next = NULL;
|
468
|
+
tmp->prev = NULL;
|
469
|
+
mempool_reserved_slice_s **pos = &mempool_reserved_pool.available;
|
470
|
+
uint8_t limit = MEMPOOL_ORDERING_LIMIT;
|
471
|
+
while (limit && *pos && ((*pos)->offset.ahead < tmp->offset.ahead)) {
|
472
|
+
tmp->prev = *pos;
|
473
|
+
pos = &(*pos)->next;
|
474
|
+
--limit;
|
475
|
+
}
|
476
|
+
if (*pos) {
|
477
|
+
tmp->next = *pos;
|
478
|
+
tmp->next->prev = tmp;
|
479
|
+
*pos = tmp;
|
480
|
+
} else {
|
481
|
+
*pos = tmp;
|
482
|
+
}
|
483
|
+
|
484
|
+
slice->offset.ahead |= MEMPOOL_USED_MARKER;
|
485
|
+
MEMPOOL_UNLOCK();
|
486
|
+
return ptr;
|
487
|
+
}
|
488
|
+
slice->offset.ahead |= MEMPOOL_USED_MARKER;
|
489
|
+
MEMPOOL_UNLOCK();
|
490
|
+
|
491
|
+
if ((slice->offset.ahead & MEMPOOL_SIZE_MASK) < size) {
|
492
|
+
void *new_mem =
|
493
|
+
mempool_malloc(size - sizeof(struct mempool_reserved_slice_s_offset));
|
494
|
+
if (!new_mem)
|
495
|
+
return NULL;
|
496
|
+
memcpy(new_mem, ptr, slice->offset.ahead & MEMPOOL_SIZE_MASK);
|
497
|
+
mempool_free(ptr);
|
498
|
+
ptr = new_mem;
|
499
|
+
}
|
500
|
+
return ptr;
|
501
|
+
|
502
|
+
realloc_indi:
|
503
|
+
/* indi doesn't shrink */
|
504
|
+
if (slice->offset.ahead > size)
|
505
|
+
return ptr;
|
506
|
+
/* reallocate indi */
|
507
|
+
void *new_mem =
|
508
|
+
mempool_malloc(size - sizeof(struct mempool_reserved_slice_s_offset));
|
509
|
+
if (!new_mem)
|
510
|
+
return NULL;
|
511
|
+
memcpy(new_mem, ptr, slice->offset.ahead & MEMPOOL_SIZE_MASK);
|
512
|
+
mempool_free(ptr);
|
513
|
+
return new_mem;
|
514
|
+
error:
|
515
|
+
errno = EFAULT;
|
516
|
+
raise(SIGSEGV); /* support longjmp rescue */
|
517
|
+
exit(EFAULT);
|
518
|
+
}
|
519
|
+
|
520
|
+
/* *****************************************************************************
|
521
|
+
********************************************************************************
|
522
|
+
TESTING
|
523
|
+
********************************************************************************
|
524
|
+
***************************************************************************** */
|
525
|
+
|
526
|
+
#if defined(DEBUG) && DEBUG == 1
|
527
|
+
|
528
|
+
#define MEMTEST_SLICE 32
|
529
|
+
|
530
|
+
#include <time.h>
|
531
|
+
static void mempool_stats(void) {
|
532
|
+
fprintf(stderr, "* Pool object: %lu bytes\n"
|
533
|
+
"* Alignment: %lu \n"
|
534
|
+
"* Minimal Allocation Size (including header): %lu\n"
|
535
|
+
"* Minimal Allocation Space (no header): %lu\n"
|
536
|
+
"* Header size: %lu\n",
|
537
|
+
sizeof(mempool_reserved_pool),
|
538
|
+
sizeof(struct mempool_reserved_slice_s_offset),
|
539
|
+
sizeof(mempool_reserved_slice_s),
|
540
|
+
sizeof(mempool_reserved_slice_s) -
|
541
|
+
sizeof(struct mempool_reserved_slice_s_offset),
|
542
|
+
sizeof(struct mempool_reserved_slice_s_offset));
|
543
|
+
}
|
544
|
+
|
545
|
+
static void mempool_speedtest(size_t memtest_repeats, void *(*mlk)(size_t),
|
546
|
+
void (*fr)(void *),
|
547
|
+
void *(*ralc)(void *, size_t)) {
|
548
|
+
void **pntrs = mlk(memtest_repeats * sizeof(*pntrs));
|
549
|
+
clock_t start, end, mlk_time, fr_time, zr_time;
|
550
|
+
mlk_time = 0;
|
551
|
+
fr_time = 0;
|
552
|
+
zr_time = 0;
|
553
|
+
struct timespec start_test, end_test;
|
554
|
+
clock_gettime(CLOCK_MONOTONIC, &start_test);
|
555
|
+
|
556
|
+
start = clock();
|
557
|
+
for (size_t i = 0; i < memtest_repeats; i++) {
|
558
|
+
__asm__ volatile("" ::: "memory");
|
559
|
+
}
|
560
|
+
end = clock();
|
561
|
+
mlk_time = end - start;
|
562
|
+
fprintf(stderr, "* Doing nothing: %lu CPU cycles.\n", mlk_time);
|
563
|
+
|
564
|
+
start = clock();
|
565
|
+
for (size_t i = 0; i < memtest_repeats; i++) {
|
566
|
+
// fprintf(stderr, "malloc %lu\n", i);
|
567
|
+
pntrs[i] = mlk(MEMTEST_SLICE);
|
568
|
+
*((uint8_t *)pntrs[i]) = 1;
|
569
|
+
}
|
570
|
+
end = clock();
|
571
|
+
mlk_time = end - start;
|
572
|
+
fprintf(stderr,
|
573
|
+
"* Allocating %lu consecutive blocks %d each: %lu CPU cycles.\n",
|
574
|
+
memtest_repeats, MEMTEST_SLICE, mlk_time);
|
575
|
+
|
576
|
+
start = clock();
|
577
|
+
for (size_t i = 0; i < memtest_repeats; i += 2) {
|
578
|
+
fr(pntrs[i]);
|
579
|
+
}
|
580
|
+
end = clock();
|
581
|
+
fr_time = end - start;
|
582
|
+
|
583
|
+
start = clock();
|
584
|
+
for (size_t i = 0; i < memtest_repeats; i += 2) {
|
585
|
+
pntrs[i] = mlk(MEMTEST_SLICE);
|
586
|
+
}
|
587
|
+
end = clock();
|
588
|
+
mlk_time = end - start;
|
589
|
+
|
590
|
+
fprintf(stderr,
|
591
|
+
"* Freeing %lu Fragmented (single space) blocks %d each: %lu CPU "
|
592
|
+
"cycles.\n",
|
593
|
+
memtest_repeats / 2, MEMTEST_SLICE, fr_time);
|
594
|
+
|
595
|
+
fprintf(stderr, "* Allocating %lu Fragmented (single space) blocks %d "
|
596
|
+
"bytes each: %lu CPU "
|
597
|
+
"cycles.\n",
|
598
|
+
memtest_repeats / 2, MEMTEST_SLICE, mlk_time);
|
599
|
+
|
600
|
+
mlk_time = 0;
|
601
|
+
fr_time = 0;
|
602
|
+
|
603
|
+
for (size_t xtimes = 0; xtimes < 100; xtimes++) {
|
604
|
+
start = clock();
|
605
|
+
for (size_t i = 0; i < memtest_repeats; i += 7) {
|
606
|
+
fr(pntrs[i]);
|
607
|
+
}
|
608
|
+
end = clock();
|
609
|
+
fr_time += end - start;
|
610
|
+
|
611
|
+
start = clock();
|
612
|
+
for (size_t i = 0; i < memtest_repeats; i += 7) {
|
613
|
+
pntrs[i] = mlk(MEMTEST_SLICE);
|
614
|
+
}
|
615
|
+
end = clock();
|
616
|
+
mlk_time += end - start;
|
617
|
+
}
|
618
|
+
|
619
|
+
fprintf(stderr,
|
620
|
+
"* 100X Freeing %lu Fragmented (7 spaces) blocks %d each: %lu CPU "
|
621
|
+
"cycles.\n",
|
622
|
+
memtest_repeats / 7, MEMTEST_SLICE, fr_time);
|
623
|
+
|
624
|
+
fprintf(stderr, "* 100X Allocating %lu Fragmented (7 spaces) blocks %d "
|
625
|
+
"bytes each: %lu CPU "
|
626
|
+
"cycles.\n",
|
627
|
+
memtest_repeats / 7, MEMTEST_SLICE, mlk_time);
|
628
|
+
|
629
|
+
start = clock();
|
630
|
+
for (size_t i = 0; i < memtest_repeats; i++) {
|
631
|
+
memset(pntrs[i], 170, MEMTEST_SLICE);
|
632
|
+
}
|
633
|
+
end = clock();
|
634
|
+
zr_time = end - start;
|
635
|
+
fprintf(stderr, "* Set bits (0b10) for %lu consecutive blocks %dB "
|
636
|
+
"each: %lu CPU cycles.\n",
|
637
|
+
memtest_repeats, MEMTEST_SLICE, zr_time);
|
638
|
+
|
639
|
+
start = clock();
|
640
|
+
for (size_t i = 0; i < memtest_repeats; i++) {
|
641
|
+
fr(pntrs[i]);
|
642
|
+
}
|
643
|
+
end = clock();
|
644
|
+
fr_time = end - start;
|
645
|
+
fprintf(stderr, "* Freeing %lu consecutive blocks %d each: %lu CPU cycles.\n",
|
646
|
+
memtest_repeats, MEMTEST_SLICE, fr_time);
|
647
|
+
|
648
|
+
start = clock();
|
649
|
+
for (size_t i = 0; i < memtest_repeats; i++) {
|
650
|
+
pntrs[i] = mlk(MEMTEST_SLICE);
|
651
|
+
}
|
652
|
+
end = clock();
|
653
|
+
start = clock();
|
654
|
+
for (size_t i = 0; i < memtest_repeats; i += 2) {
|
655
|
+
fr(pntrs[i]);
|
656
|
+
}
|
657
|
+
end = clock();
|
658
|
+
mlk_time = end - start;
|
659
|
+
fprintf(stderr,
|
660
|
+
"* Freeing every other block %dB X %lu blocks: %lu CPU cycles.\n",
|
661
|
+
MEMTEST_SLICE, memtest_repeats >> 1, mlk_time);
|
662
|
+
|
663
|
+
start = clock();
|
664
|
+
for (size_t i = 1; i < memtest_repeats; i += 2) {
|
665
|
+
pntrs[i] = ralc(pntrs[i], MEMTEST_SLICE << 1);
|
666
|
+
if (pntrs[i] == NULL)
|
667
|
+
fprintf(stderr, "REALLOC RETURNED NULL - Memory leaked during test\n");
|
668
|
+
}
|
669
|
+
end = clock();
|
670
|
+
mlk_time = end - start;
|
671
|
+
fprintf(
|
672
|
+
stderr,
|
673
|
+
"* Reallocating every other block %dB X %lu blocks: %lu CPU cycles.\n",
|
674
|
+
MEMTEST_SLICE, memtest_repeats >> 1, mlk_time);
|
675
|
+
|
676
|
+
start = clock();
|
677
|
+
for (size_t i = 1; i < memtest_repeats; i += 2) {
|
678
|
+
fr(pntrs[i]);
|
679
|
+
}
|
680
|
+
end = clock();
|
681
|
+
mlk_time = end - start;
|
682
|
+
fprintf(stderr,
|
683
|
+
"* Freeing every other block %dB X %lu blocks: %lu CPU cycles.\n",
|
684
|
+
MEMTEST_SLICE, memtest_repeats >> 1, mlk_time);
|
685
|
+
|
686
|
+
start = clock();
|
687
|
+
for (size_t i = 0; i < memtest_repeats; i++) {
|
688
|
+
pntrs[i] = mlk(MEMTEST_SLICE);
|
689
|
+
}
|
690
|
+
end = clock();
|
691
|
+
mlk_time = end - start;
|
692
|
+
fprintf(stderr,
|
693
|
+
"* Allocating %lu consecutive blocks %d each: %lu CPU cycles.\n",
|
694
|
+
memtest_repeats, MEMTEST_SLICE, mlk_time);
|
695
|
+
start = clock();
|
696
|
+
for (size_t i = 0; i < memtest_repeats; i++) {
|
697
|
+
fr(pntrs[i]);
|
698
|
+
}
|
699
|
+
end = clock();
|
700
|
+
fr_time = end - start;
|
701
|
+
fprintf(stderr, "* Freeing %lu consecutive blocks %d each: %lu CPU cycles.\n",
|
702
|
+
memtest_repeats, MEMTEST_SLICE, fr_time);
|
703
|
+
fprintf(stderr, "* Freeing pointer array %p.\n", pntrs);
|
704
|
+
fr(pntrs);
|
705
|
+
|
706
|
+
clock_gettime(CLOCK_MONOTONIC, &end_test);
|
707
|
+
uint64_t msec_for_test =
|
708
|
+
(end_test.tv_nsec < start_test.tv_nsec)
|
709
|
+
? ((end_test.tv_sec -= 1), (start_test.tv_nsec - end_test.tv_nsec))
|
710
|
+
: (end_test.tv_nsec - start_test.tv_nsec);
|
711
|
+
uint64_t sec_for_test = end_test.tv_sec - start_test.tv_sec;
|
712
|
+
|
713
|
+
fprintf(stderr, "Finished test in %llum, %llus %llu mili.sec.\n",
|
714
|
+
sec_for_test / 60, sec_for_test - (((sec_for_test) / 60) * 60),
|
715
|
+
msec_for_test / 1000000);
|
716
|
+
}
|
717
|
+
|
718
|
+
static __unused void mempool_test(void) {
|
719
|
+
fprintf(stderr, "*****************************\n");
|
720
|
+
fprintf(stderr, "mempool implementation details:\n");
|
721
|
+
mempool_stats();
|
722
|
+
fprintf(stderr, "*****************************\n");
|
723
|
+
fprintf(stderr, "System memory test for ~2Mb\n");
|
724
|
+
mempool_speedtest((2 << 20) / MEMTEST_SLICE, malloc, free, realloc);
|
725
|
+
fprintf(stderr, "*****************************\n");
|
726
|
+
fprintf(stderr, " mempool memory test for ~2Mb\n");
|
727
|
+
mempool_speedtest((2 << 20) / MEMTEST_SLICE, mempool_malloc, mempool_free,
|
728
|
+
mempool_realloc);
|
729
|
+
fprintf(stderr, "*****************************\n");
|
730
|
+
fprintf(stderr, "System memory test for ~4Mb\n");
|
731
|
+
mempool_speedtest((2 << 21) / MEMTEST_SLICE, malloc, free, realloc);
|
732
|
+
fprintf(stderr, "*****************************\n");
|
733
|
+
fprintf(stderr, " mempool memory test for ~4Mb\n");
|
734
|
+
mempool_speedtest((2 << 21) / MEMTEST_SLICE, mempool_malloc, mempool_free,
|
735
|
+
mempool_realloc);
|
736
|
+
fprintf(stderr, "*****************************\n");
|
737
|
+
fprintf(stderr, "System memory test for ~8Mb\n");
|
738
|
+
mempool_speedtest((2 << 22) / MEMTEST_SLICE, malloc, free, realloc);
|
739
|
+
fprintf(stderr, "*****************************\n");
|
740
|
+
fprintf(stderr, " mempool memory test for ~8Mb\n");
|
741
|
+
mempool_speedtest((2 << 22) / MEMTEST_SLICE, mempool_malloc, mempool_free,
|
742
|
+
mempool_realloc);
|
743
|
+
fprintf(stderr, "*****************************\n");
|
744
|
+
fprintf(stderr, "System memory test for ~16Mb\n");
|
745
|
+
mempool_speedtest((2 << 23) / MEMTEST_SLICE, malloc, free, realloc);
|
746
|
+
fprintf(stderr, "*****************************\n");
|
747
|
+
fprintf(stderr, " mempool memory test for ~16Mb\n");
|
748
|
+
mempool_speedtest((2 << 23) / MEMTEST_SLICE, mempool_malloc, mempool_free,
|
749
|
+
mempool_realloc);
|
750
|
+
fprintf(stderr, "*****************************\n");
|
751
|
+
|
752
|
+
fprintf(stderr, "*****************************\n");
|
753
|
+
fprintf(stderr, "Stressing the system\n");
|
754
|
+
fprintf(stderr, "*****************************\n");
|
755
|
+
size_t repeat = 1024 * 1024 * 16;
|
756
|
+
size_t unit = 16;
|
757
|
+
struct timespec start_test, end_test;
|
758
|
+
clock_t start, end;
|
759
|
+
fprintf(stderr, "Stress allocation/deallocation using "
|
760
|
+
"1:5 fragmentation of ~134Mb:\n");
|
761
|
+
while (repeat >= 1024) {
|
762
|
+
fprintf(stderr, " * %lu X %lu bytes", repeat, unit);
|
763
|
+
clock_gettime(CLOCK_MONOTONIC, &start_test);
|
764
|
+
start = clock();
|
765
|
+
void **ptrs = mempool_malloc(repeat * sizeof(void *));
|
766
|
+
for (size_t i = 0; i < repeat; i++) {
|
767
|
+
ptrs[i] = mempool_malloc(unit);
|
768
|
+
}
|
769
|
+
for (size_t i = 0; i < repeat; i += 5) {
|
770
|
+
mempool_free(ptrs[i]);
|
771
|
+
}
|
772
|
+
for (size_t i = 1; i < repeat; i += 5) {
|
773
|
+
mempool_free(ptrs[i]);
|
774
|
+
}
|
775
|
+
for (size_t i = 2; i < repeat; i += 5) {
|
776
|
+
mempool_free(ptrs[i]);
|
777
|
+
}
|
778
|
+
for (size_t i = 3; i < repeat; i += 5) {
|
779
|
+
mempool_free(ptrs[i]);
|
780
|
+
}
|
781
|
+
for (size_t i = 4; i < repeat; i += 5) {
|
782
|
+
mempool_free(ptrs[i]);
|
783
|
+
}
|
784
|
+
for (size_t i = 0; i < repeat; i++) {
|
785
|
+
ptrs[i] = mempool_malloc(unit);
|
786
|
+
}
|
787
|
+
for (size_t i = 0; i < repeat; i++) {
|
788
|
+
mempool_free(ptrs[i]);
|
789
|
+
}
|
790
|
+
mempool_free(ptrs);
|
791
|
+
end = clock();
|
792
|
+
clock_gettime(CLOCK_MONOTONIC, &end_test);
|
793
|
+
uint64_t msec_for_test =
|
794
|
+
(end_test.tv_nsec < start_test.tv_nsec)
|
795
|
+
? ((end_test.tv_sec -= 1), (start_test.tv_nsec - end_test.tv_nsec))
|
796
|
+
: (end_test.tv_nsec - start_test.tv_nsec);
|
797
|
+
uint64_t sec_for_test = end_test.tv_sec - start_test.tv_sec;
|
798
|
+
|
799
|
+
fprintf(stderr, " %llum, %llus %llu mili.sec. ( %lu CPU)\n",
|
800
|
+
sec_for_test / 60, sec_for_test - (((sec_for_test) / 60) * 60),
|
801
|
+
msec_for_test / 1000000, end - start);
|
802
|
+
|
803
|
+
unit <<= 1;
|
804
|
+
repeat >>= 1;
|
805
|
+
}
|
806
|
+
}
|
807
|
+
|
808
|
+
#undef MEMTEST_SLICE
|
809
|
+
|
810
|
+
#endif
|
811
|
+
|
812
|
+
/* *****************************************************************************
|
813
|
+
Cleanup
|
814
|
+
*/
|
815
|
+
#undef MEMPOOL_BLOCK_SIZE
|
816
|
+
#undef MEMPOOL_ALLOC_SPECIAL
|
817
|
+
#undef MEMPOOL_DEALLOC_SPECIAL
|
818
|
+
#undef MEMPOOL_SIZE_MASK
|
819
|
+
#undef MEMPOOL_USED_MARKER
|
820
|
+
#undef MEMPOOL_INDI_MARKER
|
821
|
+
#undef MEMPOOL_SLICE2PTR
|
822
|
+
#undef MEMPOOL_PTR2SLICE
|
823
|
+
#undef MEMPOOL_LOCK
|
824
|
+
#undef MEMPOOL_UNLOCK
|
825
|
+
#undef MEMPOOL_ORDERING_LIMIT
|
826
|
+
#endif
|