1 /*
2  * Contribution from Aleksandar Lazic <al-haproxy@none.at>
3  *
4  * Build with :
5  *   gcc -O2 -o test_pools test_pools.c
6  * or with dlmalloc too :
7  *   gcc -O2 -o test_pools -D USE_DLMALLOC test_pools.c -DUSE_DL_PREFIX dlmalloc.c
8  */
9 
10 #include <sys/time.h>
11 #include <time.h>
12 #include <stdlib.h>
13 #include <stdbool.h>
14 #include <string.h>
15 #include <stdio.h>
16 
timeval_current(void)17 static struct timeval timeval_current(void)
18 {
19 	struct timeval tv;
20 	gettimeofday(&tv, NULL);
21 	return tv;
22 }
23 
timeval_elapsed(struct timeval * tv)24 static double timeval_elapsed(struct timeval *tv)
25 {
26 	struct timeval tv2 = timeval_current();
27 	return (tv2.tv_sec - tv->tv_sec) +
28 	       (tv2.tv_usec - tv->tv_usec)*1.0e-6;
29 }
30 
31 #define torture_assert(test, expr, str) if (!(expr)) { \
32 	printf("failure: %s [\n%s: Expression %s failed: %s\n]\n", \
33 		test, __location__, #expr, str); \
34 	return false; \
35 }
36 
37 #define torture_assert_str_equal(test, arg1, arg2, desc) \
38 	if (strcmp(arg1, arg2)) { \
39 		printf("failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \
40 		   test, __location__, arg1, arg2, desc); \
41 		return false; \
42 	}
43 
44 /* added pools from haproxy */
45 #include <stdlib.h>
46 
47 /*
48  * Returns a pointer to an area of <__len> bytes taken from the pool <pool> or
49  * dynamically allocated. In the first case, <__pool> is updated to point to
50  * the next element in the list.
51  */
52 #define pool_alloc_from(__pool, __len)                      \
53 ({                                                          \
54         void *__p;                                          \
55         if ((__p = (__pool)) == NULL)                       \
56                 __p = malloc(((__len) >= sizeof (void *)) ? \
57                       (__len) : sizeof(void *));            \
58         else {                                              \
59                 __pool = *(void **)(__pool);                \
60         }                                                   \
61         __p;                                                \
62 })
63 
64 /*
65  * Puts a memory area back to the corresponding pool.
66  * Items are chained directly through a pointer that
67  * is written in the beginning of the memory area, so
68  * there's no need for any carrier cell. This implies
69  * that each memory area is at least as big as one
70  * pointer.
71  */
72 #define pool_free_to(__pool, __ptr)             \
73 ({                                              \
74         *(void **)(__ptr) = (void *)(__pool);   \
75         __pool = (void *)(__ptr);               \
76 })
77 
78 /*
79  * Returns a pointer to type <type> taken from the
80  * pool <pool_type> or dynamically allocated. In the
81  * first case, <pool_type> is updated to point to the
82  * next element in the list.
83  */
84 #define pool_alloc(type)                                \
85 ({                                                      \
86         void *__p;                                      \
87         if ((__p = pool_##type) == NULL)                \
88                 __p = malloc(sizeof_##type);            \
89         else {                                          \
90                 pool_##type = *(void **)pool_##type;	\
91         }                                               \
92         __p;                                            \
93 })
94 
95 /*
96  * Puts a memory area back to the corresponding pool.
97  * Items are chained directly through a pointer that
98  * is written in the beginning of the memory area, so
99  * there's no need for any carrier cell. This implies
100  * that each memory area is at least as big as one
101  * pointer.
102  */
103 #define pool_free(type, ptr)                            \
104 ({                                                      \
105         *(void **)ptr = (void *)pool_##type;            \
106         pool_##type = (void *)ptr;                      \
107 })
108 
109 /*
110  * This function destroys a pull by freeing it completely.
111  * This should be called only under extreme circumstances.
112  */
pool_destroy(void ** pool)113 static inline void pool_destroy(void **pool)
114 {
115 	void *temp, *next;
116 	next = pool;
117 	while (next) {
118 		temp = next;
119 		next = *(void **)temp;
120 		free(temp);
121 	}
122 }
123 
124 #define sizeof_talloc   1000
125 
126 /*
127   measure the speed of hapx versus malloc
128 */
test_speed1(void)129 static bool test_speed1(void)
130 {
131         void **pool_talloc = NULL;
132 	void *ctx = pool_alloc(talloc);
133 	unsigned count;
134 	const int loop = 1000;
135 	int i;
136 	struct timeval tv;
137 
138 	printf("test: speed [\nhaproxy-pool VS MALLOC SPEED 2\n]\n");
139 
140 	tv = timeval_current();
141 	count = 0;
142 	do {
143 		void *p1, *p2, *p3;
144 		for (i=0;i<loop;i++) {
145 			p1 = pool_alloc_from(pool_talloc, 10 + loop % 100);
146 			p2 = pool_alloc_from(pool_talloc, strlen("foo bar") + 1);
147 			strcpy(p2, "foo bar");
148 			p3 = pool_alloc_from(pool_talloc, 300);
149 			pool_free_to(pool_talloc,p1);
150 			pool_free_to(pool_talloc,p3);
151 			pool_free_to(pool_talloc,p2);
152 		}
153 		count += 3 * loop;
154 	} while (timeval_elapsed(&tv) < 5.0);
155 
156 	fprintf(stderr, "haproxy : %10.0f ops/sec\n", count/timeval_elapsed(&tv));
157 
158         pool_destroy(pool_talloc);
159 
160 	tv = timeval_current();
161 	count = 0;
162 	do {
163 		void *p1, *p2, *p3;
164 		for (i=0;i<loop;i++) {
165 			p1 = malloc(10 + loop % 100);
166 			p2 = malloc(strlen("foo bar") + 1);
167 			strcpy(p2, "foo bar");
168 			p3 = malloc(300);
169 			free(p1);
170 			free(p2);
171 			free(p3);
172 		}
173 		count += 3 * loop;
174 	} while (timeval_elapsed(&tv) < 5.0);
175 	fprintf(stderr, "malloc  : %10.0f ops/sec\n", count/timeval_elapsed(&tv));
176 
177 #ifdef USE_DLMALLOC
178 	tv = timeval_current();
179 	count = 0;
180 	do {
181 		void *p1, *p2, *p3;
182 		for (i=0;i<loop;i++) {
183 			p1 = dlmalloc(10 + loop % 100);
184 			p2 = dlmalloc(strlen("foo bar") + 1);
185 			strcpy(p2, "foo bar");
186 			p3 = dlmalloc(300);
187 			dlfree(p1);
188 			dlfree(p2);
189 			dlfree(p3);
190 		}
191 		count += 3 * loop;
192 	} while (timeval_elapsed(&tv) < 5.0);
193 	fprintf(stderr, "dlmalloc: %10.0f ops/sec\n", count/timeval_elapsed(&tv));
194 #endif
195 
196 	printf("success: speed1\n");
197 
198 	return true;
199 }
200 
main(void)201 int main(void)
202 {
203 	bool ret = test_speed1();
204 	if (!ret)
205 		return -1;
206 	return 0;
207 }
208