Add support for custom peer loop
[archipelago] / xseg / peers / user / bench-xseg.c
1 /*
2  * Copyright 2012 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *   2. Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer in the documentation and/or other materials
14  *      provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * The views and conclusions contained in the software and
30  * documentation are those of the authors and should not be
31  * interpreted as representing official policies, either expressed
32  * or implied, of GRNET S.A.
33  */
34
35 #define _GNU_SOURCE
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <sys/syscall.h>
40 #include <sys/types.h>
41 #include <pthread.h>
42 #include <xseg/xseg.h>
43 #include <peer.h>
44 #include <time.h>
45 #include <sys/util.h>
46 #include <signal.h>
47
48 struct timespec delay = {0, 4000000};
49
50 struct bench {
51         uint64_t ts; //Total I/O size
52         uint64_t os; //Object size
53         uint64_t bs; //Block size
54         uint32_t iodepth; //Num of in-flight xseg reqs
55         xport dst_port;
56         uint8_t flags;
57 };
58
59 int custom_peerd_loop(struct peerd *peer);
60
61 #define MAX_ARG_LEN 10
62
63 void custom_peer_usage()
64 {
65         fprintf(stderr, "Custom peer options: \n"
66                 "  --------------------------------------------\n"
67                 "    -ts       | None    | Total I/O size\n"
68                 "    -os       | 4M      | Object size\n"
69                 "    -bs       | 4k      | Block size\n"
70                 "    -dp       | None    | Destination port\n"
71                 "    --iodepth | 1       | Number of in-flight I/O requests\n"
72                 "\n");
73 }
74
75 /*
76  * Convert string to size in bytes.
77  * If syntax is invalid, return 0. Values such as zero and non-integer
78  * multiples of segment's page size should not be accepted.
79  */
80 static uint64_t str2num(char *str)
81 {
82         char *unit;
83         uint64_t num;
84
85         num = strtoll(str, &unit, 10);
86         if (strlen(unit) > 1) //Invalid syntax
87                 return 0;
88         else if (strlen(unit) < 1) //Plain number in bytes
89                 return num;
90
91         switch (*unit) {
92                 case 'g':
93                 case 'G':
94                         num *= 1024;
95                 case 'm':
96                 case 'M':
97                         num *= 1024;
98                 case 'k':
99                 case 'K':
100                         num *= 1024;
101                         break;
102                 default:
103                         num = 0;
104         }
105         return num;
106 }
107
108 int custom_peer_init(struct peerd *peer, int argc, char *argv[])
109 {
110         struct bench *prefs;
111         char total_size[MAX_ARG_LEN + 1];
112         char object_size[MAX_ARG_LEN + 1];
113         char block_size[MAX_ARG_LEN + 1];
114         struct xseg *xseg = peer->xseg;
115         unsigned int xseg_page_size = 1 << xseg->config.page_shift;
116         long dst_port = -1;
117
118         total_size[0] = 0;
119         block_size[0] = 0;
120         object_size[0] = 0;
121
122         prefs = malloc(sizeof(struct bench));
123         if (!prefs) {
124                 perror("malloc");
125                 return -1;
126         }
127
128         //Begin reading the benchmark-specific arguments
129         BEGIN_READ_ARGS(argc, argv);
130         READ_ARG_STRING("-ts", total_size, MAX_ARG_LEN);
131         READ_ARG_STRING("-os", object_size, MAX_ARG_LEN);
132         READ_ARG_STRING("-bs", block_size, MAX_ARG_LEN);
133         READ_ARG_ULONG("--iodepth", prefs->iodepth);
134         READ_ARG_ULONG("-dp", dst_port);
135         END_READ_ARGS();
136
137         /*
138          *************************
139          * Check size parameters *
140          *************************
141          */
142
143         //Block size (bs): Defaults to 4K.
144         //It must be a number followed by one of these characters: [k|K|m|M|g|G].
145         //If not, it will be considered as size in bytes.
146         //Must be integer multiple of segment's page size (typically 4k).
147         if (!block_size[0])
148                 strcpy(block_size,"4k");
149
150         prefs->bs = str2num(block_size);
151         if (!prefs->bs) {
152                 XSEGLOG2(&lc, E, "Invalid syntax: %s\n", block_size);
153                 goto arg_fail;
154         } else if (prefs->bs % xseg_page_size) {
155                 XSEGLOG2(&lc, E, "Misaligned block size: %s\n", block_size);
156                 goto arg_fail;
157         }
158
159         //Total I/O size (ts): Must be supplied by user.
160         //Must have the same format as "total size"
161         //Must be integer multiple of "block size"
162         if (!total_size[0]) {
163                 XSEGLOG2(&lc, E, "Total I/O size needs to be supplied\n");
164                 goto arg_fail;
165         }
166
167         prefs->ts = str2num(total_size);
168         if (!prefs->ts) {
169                 XSEGLOG2(&lc, E, "Invalid syntax: %s\n", total_size);
170                 goto arg_fail;
171         } else if (prefs->ts % prefs->bs) {
172                 XSEGLOG2(&lc, E, "Misaligned total I/O size: %s\n", total_size);
173                 goto arg_fail;
174         } else if (prefs->ts > xseg->segment_size) {
175                 XSEGLOG2(&lc, E, "Total I/O size exceeds segment size\n", total_size);
176                 goto arg_fail;
177         }
178
179         //Object size (os): Defaults to 4M.
180         //Must have the same format as "total size"
181         //Must be integer multiple of "block size"
182         if (!object_size[0])
183                 strcpy(object_size,"4M");
184
185         prefs->os = str2num(object_size);
186         if (!prefs->os) {
187                 XSEGLOG2(&lc, E, "Invalid syntax: %s\n", object_size);
188                 goto arg_fail;
189         } else if (prefs->os % prefs->bs) {
190                 XSEGLOG2(&lc, E, "Misaligned object size: %s\n", object_size);
191                 goto arg_fail;
192         }
193
194         /*
195          *************************
196          * Check port parameters *
197          *************************
198          */
199
200         if (dst_port < 0){
201                 XSEGLOG2(&lc, E, "Destination port needs to be supplied\n");
202                 goto arg_fail;
203         }
204
205         prefs->dst_port = (xport) dst_port;
206
207         /*
208          **************************
209          * Customize struct peerd *
210          **************************
211          */
212
213         peer->custom_peerd_loop = custom_peerd_loop;
214         peer->priv = (void *) prefs;
215         return 0;
216
217 arg_fail:
218         free(prefs);
219         custom_peer_usage();
220         return -1;
221 }
222
223 /*
224  * This function substitutes the default peerd_loop of peer.c.
225  * This is achieved by passing to gcc a CUSTOM_LOOP macro definition which is
226  * checked (ifdef) in peer.c
227  */
228 int custom_peerd_loop(struct peerd *peer)
229 {
230 #ifdef MT
231         int i;
232         if (peer->interactive_func)
233                 peer->interactive_func();
234         for (i = 0; i < peer->nr_threads; i++) {
235                 pthread_join(peer->thread[i].tid, NULL);
236         }
237 #else
238         struct xseg *xseg = peer->xseg;
239         struct bench *prefs = peer->priv;
240
241         xport portno_start = peer->portno_start;
242         xport portno_end = peer->portno_end;
243         uint64_t threshold=1000/(1 + portno_end - portno_start);
244         pid_t pid =syscall(SYS_gettid);
245         uint64_t loops;
246
247         uint64_t remaining = prefs->ts;
248
249         XSEGLOG2(&lc, I, "Peer has tid %u.\n", pid);
250         xseg_init_local_signal(xseg, peer->portno_start);
251
252         while (!isTerminate()
253                         && xq_count(&peer->free_reqs) == peer->nr_ops
254                         && remaining) {
255                 for (loops= threshold; loops > 0; loops--) {
256                         if (loops == 1)
257                                 xseg_prepare_wait(xseg, peer->portno_start);
258                         if (check_ports(peer))
259                                 loops = threshold;
260                 }
261 #ifdef ST_THREADS
262                 if (ta){
263                         st_sleep(0);
264                         continue;
265                 }
266 #endif
267                 XSEGLOG2(&lc, I, "Peer goes to sleep\n");
268                 xseg_wait_signal(xseg, 10000000UL);
269                 xseg_cancel_wait(xseg, peer->portno_start);
270                 XSEGLOG2(&lc, I, "Peer woke up\n");
271         }
272         custom_peer_finalize(peer);
273         xseg_quit_local_signal(xseg, peer->portno_start);
274 #endif
275         return 0;
276 }
277
278 void custom_peer_finalize(struct peerd *peer)
279 {
280         return;
281 }
282
283 int dispatch(struct peerd *peer, struct peer_req *pr, struct xseg_request *req,
284                 enum dispatch_reason reason)
285 {
286         if (canDefer(peer))
287                 defer_request(peer, pr);
288         else {
289 //              printf("completing req id: %u (remote %u)\n", (unsigned int) (pr - peer->peer_reqs), (unsigned int) pr->req->priv);
290 //              nanosleep(&delay,NULL);
291 //              print_req(peer->xseg, pr->req);
292                 complete(peer, pr);
293         }
294         return 0;
295 }