1 /* -*- mode: c -*-
2 *
3 * Alternatve version of the strcat test using the vstr string library ...
4 * http://www.and.org/vstr/
5 * gcc -Wall -W -O2 -o tst tst.c `pkg-config --cflags --libs vstr`
6 *
7 * http://www.bagley.org/~doug/shootout/
8 */
9 /* #define VSTR_COMPILE_INLINE 0 */
10 #include <vstr.h>
11
12 #include <errno.h>
13 #include <err.h>
14 #include <assert.h>
15
16 #include "ex_perf.h"
17
18 #define HAVE_IOV 0
19 #define FMT_ALL 0
20
21 #define MCPY_TYPE MCPY_GCC
22
23 static const char *mcpy_type_map[3] = {
24 #define MCPY_LIBC 0
25 "MCPY_LIBC",
26 #define MCPY_GCC 1
27 "MCPY_GCC",
28 #define MCPY_VSTR 2
29 "MCPY_VSTR",
30 };
31
32 #if MCPY_TYPE == MCPY_LIBC
33 # define MCPY(x, y, z) memcpy(x, y, z)
34 #elif MCPY_TYPE == MCPY_GCC
35 # define MCPY(x, y, z) __builtin_memcpy(x, y, z)
36 #elif MCPY_TYPE == MCPY_VSTR
37 # define MCPY(x, y, z) vstr_wrap_memcpy(x, y, z)
38 #else
39 # error "Not a valid MCPY_TYPE"
40 #endif
41
42 #define BUF_SZ (4 * 1024) /* size of node */
43
44 #define STUFF "hello\n" /* size of data to append each time -- from shootout */
45
46 #define YES_NO(x) ((x) ? "yes" : "no")
47
hand_inline(Vstr_base * tst,unsigned int num)48 static void hand_inline(Vstr_base *tst, unsigned int num)
49 {
50 unsigned int scan = 0;
51
52 while (scan < num)
53 {
54 size_t len = tst->end ? (BUF_SZ - tst->end->len) : 0;
55
56 if (len >= strlen(STUFF))
57 { /* hand inline of vstr_add_cstr_buf()...
58 * massive hack -- DO NOT rely on this working this is just so we can
59 * mesure the best possible inline perf. */
60 unsigned int orig = scan;
61 char *buf = ((Vstr_node_buf *)tst->end)->buf;
62
63 buf += tst->end->len;
64 while (len >= strlen(STUFF))
65 {
66 MCPY(buf, STUFF, strlen(STUFF));
67 buf += strlen(STUFF);
68 len -= strlen(STUFF);
69
70 if (++scan == num)
71 break;
72 }
73
74 len = (scan - orig) * strlen(STUFF);
75 tst->len += len;
76 tst->end->len += len;
77 if (tst->iovec_upto_date)
78 {
79 unsigned int num_off = tst->num + VSTR__CACHE(tst)->vec->off - 1;
80 VSTR__CACHE(tst)->vec->v[num_off].iov_len += len;
81 }
82 }
83
84 vstr_add_cstr_buf(tst, tst->len, STUFF);
85 ++scan;
86 }
87 }
88
hand_iov(Vstr_base * tst,unsigned int num)89 static void hand_iov(Vstr_base *tst, unsigned int num)
90 {
91 unsigned int scan = 0;
92
93 while (scan < num)
94 {
95 struct iovec *iov = NULL;
96 unsigned int iov_num = 0;
97 size_t len = 0;
98
99 if (!vstr_add_iovec_buf_beg(tst, tst->len, 1, 2, &iov, &iov_num))
100 errno = ENOMEM, err(EXIT_FAILURE, "iovec_buf_beg");
101
102 assert(iov_num);
103
104 len = iov[0].iov_len;
105
106 if (len < strlen(STUFF))
107 vstr_add_cstr_buf(tst, tst->len, STUFF);
108 else
109 { /* hand inline using iovectors */
110 unsigned int orig = scan;
111 char *buf = iov[0].iov_base;
112
113 while (len >= strlen(STUFF))
114 {
115 MCPY(buf, STUFF, strlen(STUFF));
116 buf += strlen(STUFF);
117 len -= strlen(STUFF);
118
119 if (++scan >= num)
120 break;
121 }
122 assert(scan <= num);
123
124 len = (scan - orig) * strlen(STUFF);
125 vstr_add_iovec_buf_end(tst, tst->len, len);
126 }
127
128 ++scan;
129 }
130 }
131
del(Vstr_base * tst)132 static void del(Vstr_base *tst)
133 {
134 vstr_del(tst, 1, tst->len);
135 }
del_alloc(Vstr_base * tst)136 static void del_alloc(Vstr_base *tst)
137 {
138 unsigned int num = tst->num;
139 vstr_del(tst, 1, tst->len);
140 vstr_free_spare_nodes(tst->conf, VSTR_TYPE_NODE_BUF, num);
141 }
142
main(int argc,char * argv[])143 int main(int argc, char *argv[])
144 {
145 unsigned int num = ((argc == 2) ? atoi(argv[1]) : 1);
146 Vstr_base *tst = NULL;
147 Vstr_base *out = NULL;
148
149 if (!vstr_init())
150 errno = ENOMEM, err(EXIT_FAILURE, "vstr_init");
151
152 vstr_cntl_conf(NULL, VSTR_CNTL_CONF_SET_NUM_BUF_SZ, BUF_SZ);
153
154 if (!(tst = vstr_make_base(NULL)))
155 errno = ENOMEM, err(EXIT_FAILURE, "vstr_make_base");
156 if (!(out = vstr_make_base(NULL)))
157 errno = ENOMEM, err(EXIT_FAILURE, "vstr_make_base");
158
159 vstr_cntl_conf(out->conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '$');
160
161 if (FMT_ALL)
162 vstr_sc_fmt_add_all(out->conf);
163 else
164 {
165 vstr_sc_fmt_add_buf(out->conf, "{buf:%s%zu}");
166 vstr_sc_fmt_add_rep_chr(out->conf, "{rep_chr:%c%zu}"); /* for TST_HDR */
167 }
168
169 vstr_cntl_conf(out->conf, VSTR_CNTL_CONF_SET_LOC_CSTR_THOU_SEP, "_");
170 vstr_cntl_conf(out->conf, VSTR_CNTL_CONF_SET_LOC_CSTR_THOU_GRP, "\3");
171
172 if (HAVE_IOV)
173 {
174 vstr_add_rep_chr(tst, 0, '-', strlen(STUFF) * num);
175 vstr_export_iovec_ptr_all(tst, NULL, NULL);
176 }
177 vstr_del(tst, 1, tst->len);
178 vstr_free_spare_nodes(tst->conf, VSTR_TYPE_NODE_BUF, 1000 * 1000 * 1000);
179
180 TST_HDR_BEG();
181
182 if (0) {
183 del_alloc(tst); TST_BEG(1, 1);
184 hand_inline(tst, num);
185 TST_END("hand inline (alloc)");
186 del(tst); TST_BEG(1, 1);
187 hand_inline(tst, num);
188 TST_END("hand inline");
189
190 del_alloc(tst); TST_BEG(1, 1);
191 hand_iov(tst, num);
192 TST_END("iov inline (alloc)");
193 del(tst); TST_BEG(1, 1);
194 hand_iov(tst, num);
195 TST_END("iov inline");
196
197 del_alloc(tst); TST_BEG(1, num);
198 vstr_add_cstr_buf(tst, tst->len, STUFF);
199 TST_END("add_cstr_buf (alloc)");
200 del(tst); TST_BEG(1, num);
201 vstr_add_cstr_buf(tst, tst->len, STUFF);
202 TST_END("add_cstr_buf");
203 }
204
205 del_alloc(tst); TST_BEG(1, num);
206 vstr_add_fmt(tst, tst->len, "%s", STUFF);
207 TST_END("add_fmt(%s) (alloc)");
208 del(tst); TST_BEG(1, num);
209 vstr_add_fmt(tst, tst->len, "%s", STUFF);
210 TST_END("add_fmt(%s)");
211
212 del_alloc(tst); TST_BEG(1, num);
213 vstr_add_fmt(tst, tst->len, "${buf:%s%zu}", STUFF, strlen(STUFF));
214 TST_END("add_fmt(${buf}) (alloc)");
215 del(tst); TST_BEG(1, num);
216 vstr_add_fmt(tst, tst->len, "${buf:%s%zu}", STUFF, strlen(STUFF));
217 TST_END("add_fmt(${buf})");
218
219 TST_HDR_END();
220
221 vstr_add_fmt(out, out->len, "data = %c%s%c\n", '"', STUFF, '"');
222 vstr_add_fmt(out, out->len, "iter = %'13u\n", num);
223 vstr_add_fmt(out, out->len, "len = %'13zu\n", tst->len);
224 vstr_add_fmt(out, out->len, "num = %'13u\n", tst->num);
225 vstr_add_fmt(out, out->len, "hand inline = %s\n", mcpy_type_map[MCPY_TYPE]);
226 vstr_add_fmt(out, out->len, "have iov = %s\n", YES_NO(HAVE_IOV));
227 vstr_add_fmt(out, out->len, "vstr inline = %s\n",
228 YES_NO(VSTR_COMPILE_INLINE));
229
230 if (out->conf->malloc_bad)
231 errno = ENOMEM, err(EXIT_FAILURE, "tst");
232
233 while (out->len)
234 if (!vstr_sc_write_fd(out, 1, out->len, 1, NULL))
235 err(EXIT_FAILURE, "write");
236
237 vstr_free_base(tst);
238 vstr_free_base(out);
239 vstr_exit();
240
241 exit (EXIT_SUCCESS);
242 }
243