1 /* This file tests how efficient differrent lengths of _BUF nodes are and also
2  * compares them to one big pile
3  * -- vstr is kind of built on the idea that this isn't a problem for
4  *    reasonable sizes */
5 
6 #define VSTR_COMPILE_INCLUDE 1
7 
8 #include <vstr.h>
9 
10 #if 0
11 # define TST_SZ_BEG (64 - (16 + 8))
12 # define TST_SZ_INC ((sz == (64 - (16 + 8)))   ? (16 + 8) : \
13                      (sz == 64)                ? (64 - (16 + 8)) : \
14                      (sz == (128 - (16 + 8)))  ? (16 + 8) : \
15                      (sz == 128)               ? (128 - (16 + 8)) : \
16                      (sz == (256 - (16 + 8)))  ? (16 + 8) : \
17                      (sz == 256)               ? (256 - (16 + 8)) : \
18                      (sz == (512 - (16 + 8)))  ? (16 + 8) : \
19                      (sz == 512)               ? (512 - (16 + 8)) : \
20                      (sz == (1024 - (16 + 8))) ? (16 + 8) : \
21                      (sz == 1024)              ? (3072 - (16 + 8)) : \
22                      (sz == (4096 - (16 + 8))) ? (16 + 8) : 1)
23 # define TST_SZ_END (4096)
24 #else
25 # define TST_SZ_BEG (512 - (16 + 8))
26 # define TST_SZ_INC ((sz == (512 - (16 + 8)))  ? (16 + 8) : \
27                      (sz == 512)               ? (512 + 3072 - (16 + 8)) : \
28                      (sz == (4096 - (16 + 8))) ? (16 + 8) : 1)
29 # define TST_SZ_END (4096)
30 #endif
31 
32 /* #define TST_SZ_END (4096 - (sizeof(Vstr_node) + 16)) */
33 
34 /*
35   #define TST_NUM_BEG (64)
36   #define TST_NUM_END (1024)
37 */
38 #define TST_NUM_BEG (4096)
39 #define TST_NUM_INC (1)
40 #define TST_NUM_END (4096)
41 
42 #define TST_LEN_BEG (sz >= 128 ? 128 : 1)
43 #define TST_LEN_INC (1)
44 #define TST_LEN_END (1024 * 100)
45 
46 #define TST_MALLOC_EXTRA_BEG (0)
47 #define TST_MALLOC_EXTRA_INC (1024)
48 #define TST_MALLOC_EXTRA_END (1024 * 2)
49 
50 #define TST_COUNT_BEG (1)
51 #define TST_COUNT_INC (1)
52 #define TST_COUNT_END (2)
53 
54 #define TST_USE_MEMCPY 1
55 
56 #include "ex_perf.h"
57 
58 #include <assert.h>
59 #include <unistd.h>
60 
61 #include <glib.h>
62 
63 
64  /* this is M_TRIM_THRESH */
65 #define TST_ALLOC_TRIM() do { \
66   struct mallinfo mal_info = mallinfo(); \
67   trig_trim = malloc((128 * 1024) + mal_info.fordblks); \
68   if (!trig_trim) goto failed; \
69 } while (0)
70 
71 #define TST_CLEANUP_TRIM(x) do { \
72   unsigned int clean_extra = num; \
73   \
74   if (extra) \
75     while (clean_extra--) \
76       free(mal_overhead[clean_extra]); \
77   \
78   if (x) free(trig_trim); \
79 } while (0)
80 
81 
main(void)82 int main(void)
83 {
84   Vstr_conf *conf = NULL;
85   Vstr_base *out = NULL;
86   Vstr_base *s1 = NULL;
87   char *s2 = NULL;
88   GString *s3 = NULL;
89   char *s4 = NULL;
90   unsigned int ern = 0;
91   char *mal_overhead[TST_NUM_END];
92   char *s3_data = NULL;
93 
94   mallopt(M_MMAP_MAX, 0); /* mmap() can change the results */
95 
96   if (!vstr_init())
97     exit(EXIT_FAILURE);
98 
99   conf = vstr_make_conf();
100   if (!conf)
101     exit(EXIT_FAILURE);
102 
103   out = vstr_make_base(NULL); /* used as stdio/stdout */
104   if (!out)
105     exit (EXIT_FAILURE);
106 
107   s3_data = malloc(TST_LEN_END);
108   if (!s3_data)
109     goto failed;
110   memset(s3_data, 'x', TST_LEN_END);
111 
112   vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_BUF, 128, 128);
113 
114   if (1)
115   {
116     unsigned int sz = TST_SZ_BEG;
117     while (sz <= TST_SZ_END)
118     {
119     unsigned int len = TST_LEN_BEG;
120 
121     vstr_free_base(s1);
122     vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_NUM_BUF_SZ, sz);
123     s1 = vstr_make_base(conf);
124     if (!s1)
125       goto failed;
126 
127     while (len <= TST_LEN_END)
128     {
129     unsigned int num = TST_NUM_BEG;
130     while (num <= TST_NUM_END)
131     {
132     unsigned int extra = TST_MALLOC_EXTRA_BEG;
133     while (extra <= TST_MALLOC_EXTRA_END)
134     {
135     unsigned int count = TST_COUNT_BEG;
136     while (count <= TST_COUNT_END)
137     {
138       void *trig_trim = NULL;
139 
140       TST_ALLOC_TRIM();
141 
142       TST_BEG(1, num);
143       if (extra)
144         mal_overhead[tst_count] = malloc(extra);
145       buf_out[0] = 'x';
146       if (TST_USE_MEMCPY)
147         vstr_add_buf(s1, s1->len, s3_data, len);
148       else
149         vstr_add_rep_chr(s1, s1->len, buf_out[0], len);
150       TST_CALC_END("V");
151 
152       vstr_del(s1, 1, s1->len);
153       TST_CLEANUP_TRIM(0);
154 
155       TST_BEG(1, num);
156       if (extra)
157         mal_overhead[tst_count] = malloc(extra);
158       buf_out[0] = 'x';
159       if (TST_USE_MEMCPY)
160         vstr_add_buf(s1, s1->len, s3_data, len);
161       else
162         vstr_add_rep_chr(s1, s1->len, buf_out[0], len);
163       TST_CALC_END("A");
164 
165       vstr_del(s1, 1, s1->len);
166       vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_BUF, 0, 0);
167       TST_CLEANUP_TRIM(1);
168       TST_ALLOC_TRIM();
169 
170       s2 = malloc(sz); /* single object */
171       if (!s2)
172         goto failed;
173 
174       TST_BEG(1, num);
175       unsigned int off     = (len * tst_count);
176       unsigned int new_len = off + len;
177       if (extra)
178         mal_overhead[tst_count] = malloc(extra);
179       buf_out[0] = 'x';
180       s2 = realloc(s2, new_len);
181       if (!s2)
182         goto failed;
183       if (TST_USE_MEMCPY)
184         memcpy(s2 + off, s3_data,    len);
185       else
186         memset(s2 + off, buf_out[0], len);
187       TST_CALC_END("S");
188 
189       free(s2);
190       s2 = NULL;
191       TST_CLEANUP_TRIM(1);
192       TST_ALLOC_TRIM();
193 
194       if (TST_USE_MEMCPY)
195       {
196         s3 = g_string_sized_new(sz);
197         TST_BEG(1, num);
198         if (extra)
199           mal_overhead[tst_count] = malloc(extra);
200         buf_out[0] = 'x';
201         g_string_append_len(s3, s3_data, len);
202         TST_CALC_END("G");
203 
204         g_string_free(s3, TRUE);
205         s3 = NULL;
206         TST_CLEANUP_TRIM(1);
207         TST_ALLOC_TRIM();
208 
209         TST_BEG(1, num);
210         if (extra)
211           mal_overhead[tst_count] = malloc(extra);
212         buf_out[0] = 'x';
213         vstr_add_ptr(s1, s1->len, s3_data, len);
214         TST_CALC_END("P");
215 
216         vstr_del(s1, 1, s1->len);
217         vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_PTR, 0, 0);
218         TST_CLEANUP_TRIM(1);
219         TST_ALLOC_TRIM();
220       }
221 
222       s4 = malloc(len); /* single object */
223       if (!s4)
224         goto failed;
225 
226       TST_BEG(1, num);
227       if (extra)
228         mal_overhead[tst_count] = malloc(extra);
229       buf_out[0] = 'x';
230       if (TST_USE_MEMCPY)
231         memcpy(s4, s3_data,    len);
232       else
233         memset(s4, buf_out[0], len);
234       TST_CALC_END("B");
235 
236       free(s4);
237       s4 = NULL;
238       TST_CLEANUP_TRIM(1);
239 
240       if (out->len)
241         vstr_sc_write_fd(out, 1, out->len, 1 /* stdout */, &ern);
242       if (ern)
243         goto failed;
244 
245       count += TST_COUNT_INC;
246     }
247       extra += TST_MALLOC_EXTRA_INC;
248     }
249       num   += TST_NUM_INC;
250     }
251       len   += TST_LEN_INC;
252     }
253       sz    += TST_SZ_INC;
254     }
255   }
256 
257   if (s1->conf->malloc_bad || out->conf->malloc_bad)
258     goto failed;
259 
260   while (out->len && !ern)
261     vstr_sc_write_fd(out, 1, out->len, STDOUT_FILENO, &ern);
262 
263   vstr_free_conf(conf);
264   vstr_free_base(out);
265   vstr_free_base(s1);
266   free(s2);
267 
268   vstr_exit();
269 
270   exit (EXIT_SUCCESS);
271 
272  failed:
273   ern = 0;
274   while (out->len && !ern)
275     vstr_sc_write_fd(out, 1, out->len, STDERR_FILENO, &ern);
276 
277   vstr_free_base(out);
278   vstr_free_base(s1);
279   free(s2);
280 
281   vstr_exit();
282 
283   exit (EXIT_FAILURE);
284 }
285 
286