2 * Copyright 2012 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
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.
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.
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.
36 #include <xseg/xseg.h>
40 #include <sys/syscall.h>
41 #include <sys/types.h>
47 #include <bench-xseg.h>
48 #include <bench-lfsr.h>
53 * This macro checks two things:
54 * a) If in-flight requests are less than given iodepth
55 * b) If we have submitted all of the requests
56 * c) If we are not in ping mode
57 * d) If we have been asked to terminate
59 #define CAN_SEND_REQUEST(__p) \
60 ((__p->status->submitted - __p->status->received < __p->iodepth) && \
61 (__p->status->submitted < __p->status->max) && \
62 (GET_FLAG(PING, __p->flags) == PING_MODE_OFF) && \
65 #define CAN_VERIFY(__p) \
66 ((GET_FLAG(VERIFY, __p->flags) != VERIFY_NO) && __p->op == X_READ)
68 #define CAN_PRINT_PROGRESS(__p, __nr) \
69 ((GET_FLAG(PROGRESS, __p->flags) != PROGRESS_NO) && \
70 (GET_FLAG(PING, __p->flags) == PING_MODE_OFF) && \
71 (__p->status->received == __nr))
73 void custom_peer_usage()
75 fprintf(stderr, "Custom peer options: \n"
76 " --------------------------------------------\n"
78 "a) Benchmark options: \n"
79 " --------------------------------------------\n"
80 " -op | None | XSEG operation:\n"
81 " | | [read|write|info|delete]\n"
82 " --pattern | None | I/O pattern [seq|rand]\n"
83 " -rc | None | Request cap\n"
84 " -to | None | Total objects\n"
85 " -ts | None | Total I/O size\n"
86 " -os | 4M | Object size\n"
87 " -bs | 4k | Block size\n"
88 " -tp | None | Target port\n"
89 " --iodepth | 1 | Number of in-flight I/O requests\n"
90 " --seed | None | Initialize LFSR and target names\n"
92 "b) Object naming options: \n"
93 " --------------------------------------------\n"
94 " --prefix | bench | Add a common prefix to all object names\n"
95 " --objname | None | Use only one object with this name\n"
97 "c) Data verification options: \n"
98 " --------------------------------------------\n"
99 " --verify | no | Verify written requests:\n"
100 " | | [no|meta|full]\n"
102 "d) Progress report options: \n"
103 " --------------------------------------------\n"
104 " --progress | yes | Show progress of benchmark:\n"
106 " --ptype | both | Progress report type:\n"
107 " | | [req|io|both]\n"
108 " --pinterval | 5%% | Intervals at which progress is shown\n"
109 " --insanity | sane | Adjust insanity level of benchmark:\n"
110 " | | [sane|eccentric|manic|paranoid]\n"
112 "e) Misc options: \n"
113 " --------------------------------------------\n"
114 " --ping | no | Ping target before starting:\n"
117 "Additional information:\n"
118 " --------------------------------------------\n"
119 " * The -to and -ts options are mutually exclusive\n"
121 " * The object name is always not null-terminated and\n"
122 " defaults to the following structure:\n"
123 " <prefix>-<seed>-<object number>\n"
126 " a. <prefix> is given by user or defaults to 'bench'\n"
127 " b. <seed> is given by user or defaults to a random value.\n"
128 " Its length will be 9 digits, with trailing zeros where\n"
130 " c. <object number> is out of the user's control. It is\n"
131 " calculated during the benchmark and is a 15-digit\n"
132 " number, allowing a maximum of 1 quadrillion objects\n"
134 " So, if bench is called with the arguments:\n"
135 " --prefix obj --seed 999\n"
137 " and <object number> is 9,the resulting object name will\n"
139 " obj-000000999-000000000000009\n"
141 " * The above object name structure can be bypassed with the\n"
142 " --objname <object name> argument. This implies the\n"
145 " a. -to option is strictly restricted to 1\n"
146 " b. -ts option defaults to (and can't be larger than)\n"
147 " the object size (-os argument)\n"
148 " c. --prefix is must be unused. If used, it produces an\n"
149 " error to alert the user\n"
151 " * The progress report is printed by default at intervals of\n"
153 " There are three progress types:\n"
155 " a. req: it prints the request status so far i.e. how many\n"
156 " requests have been subitted, received, failed etc.\n"
157 " b. io: it prints the bandwidth and IOPS status of the\n"
158 " elapsed 5%% of the benchmark\n"
159 " c. both: it combines the output of <req> and <io>.\n"
161 " * Interval is commonly a percentage of max requests. This\n"
162 " means that when a user gives:\n"
163 " --pinterval 33%%\n"
165 " the progress report will be printed 3 times during the\n"
166 " benchmark. Else, if the user wants to, he/she can give:\n"
167 " --pinterval 1234\n"
169 " and the progress report will be printed every 1234\n"
174 int custom_peer_init(struct peerd *peer, int argc, char *argv[])
177 char request_cap[MAX_ARG_LEN + 1];
178 char total_objects[MAX_ARG_LEN + 1];
179 char total_size[MAX_ARG_LEN + 1];
180 char object_size[MAX_ARG_LEN + 1];
181 char block_size[MAX_ARG_LEN + 1];
182 char op[MAX_ARG_LEN + 1];
183 char pattern[MAX_ARG_LEN + 1];
184 char insanity[MAX_ARG_LEN + 1];
185 char verify[MAX_ARG_LEN + 1];
186 char progress[MAX_ARG_LEN + 1];
187 char ptype[MAX_ARG_LEN + 1];
188 char pinterval[MAX_ARG_LEN + 1];
189 char ping[MAX_ARG_LEN + 1];
190 char prefix[XSEG_MAX_TARGETLEN + 1];
191 char objname[XSEG_MAX_TARGETLEN + 1];
192 struct xseg *xseg = peer->xseg;
193 struct object_vars *obv;
194 unsigned int xseg_page_size = 1 << xseg->config.page_shift;
197 unsigned long seed = -1;
198 unsigned long seed_max;
206 total_objects[0] = 0;
220 /* allocate struct bench */
221 prefs = malloc(sizeof(struct bench));
226 memset(prefs, 0, sizeof(struct bench));
228 /* allocate struct req_status */
229 prefs->status = malloc(sizeof(struct req_status));
230 if (!prefs->status) {
234 memset(prefs->status, 0, sizeof(struct req_status));
236 /* allocate struct object_name */
237 prefs->objvars = malloc(sizeof(struct object_vars));
238 if (!prefs->objvars) {
240 goto object_name_fail;
242 memset(prefs->objvars, 0, sizeof(struct object_vars));
244 /* allocate struct object_name */
245 prefs->rep = malloc(sizeof(struct progress_report));
248 goto progress_report_fail;
250 memset(prefs->rep, 0, sizeof(struct progress_report));
252 /* allocate a struct timespec for each peer request */
253 for (j = 0; j < peer->nr_ops; j++) {
254 ts = malloc(sizeof(struct timespec));
259 peer->peer_reqs[j].priv = ts;
262 //Begin reading the benchmark-specific arguments
263 BEGIN_READ_ARGS(argc, argv);
264 READ_ARG_STRING("-rc", request_cap, MAX_ARG_LEN);
265 READ_ARG_STRING("-op", op, MAX_ARG_LEN);
266 READ_ARG_STRING("--pattern", pattern, MAX_ARG_LEN);
267 READ_ARG_STRING("-to", total_objects, MAX_ARG_LEN);
268 READ_ARG_STRING("-ts", total_size, MAX_ARG_LEN);
269 READ_ARG_STRING("-os", object_size, MAX_ARG_LEN);
270 READ_ARG_STRING("-bs", block_size, MAX_ARG_LEN);
271 READ_ARG_ULONG("--iodepth", iodepth);
272 READ_ARG_ULONG("-tp", dst_port);
273 READ_ARG_ULONG("--seed", seed);
274 READ_ARG_STRING("--insanity", insanity, MAX_ARG_LEN);
275 READ_ARG_STRING("--verify", verify, MAX_ARG_LEN);
276 READ_ARG_STRING("--progress", progress, MAX_ARG_LEN);
277 READ_ARG_STRING("--ptype", ptype, MAX_ARG_LEN);
278 READ_ARG_STRING("--pinterval", pinterval, MAX_ARG_LEN);
279 READ_ARG_STRING("--ping", ping, MAX_ARG_LEN);
280 READ_ARG_STRING("--prefix", prefix, XSEG_MAX_TARGETLEN);
281 READ_ARG_STRING("--objname", objname, XSEG_MAX_TARGETLEN);
284 /********************************\
285 * Check object name parameters *
286 \********************************/
287 if (objname[0] && prefix[0]) {
288 XSEGLOG2(&lc, E, "--objname and --prefix options cannot be"
293 obv = prefs->objvars;
294 obv->seedlen = SEEDLEN;
295 obv->objnumlen = OBJNUMLEN;
297 strncpy(obv->name, objname, XSEG_MAX_TARGETLEN);
299 obv->namelen = strlen(objname);
301 if (!prefix[0]) /* In this case we use a default value */
302 strcpy(prefix, "bench");
303 strncpy(obv->prefix, prefix, XSEG_MAX_TARGETLEN);
304 obv->prefixlen = strlen(prefix);
305 /* We add 2 for the extra dashes */
306 obv->namelen = obv->prefixlen + obv->seedlen +
310 /* Only --prefix can exceed bounds since --objname is bounded */
311 if (obv->namelen > XSEG_MAX_TARGETLEN) {
312 XSEGLOG2(&lc, E, "--prefix %s: Prefix is too long.", prefix);
316 /*****************************\
317 * Check I/O type parameters *
318 \*****************************/
320 //We support 4 xseg operations: X_READ, X_WRITE, X_DELETE, X_INFO
321 //The I/O pattern of these operations can be either sequential (seq) or
324 XSEGLOG2(&lc, E, "xseg operation needs to be supplied\n");
329 XSEGLOG2(&lc, E, "Invalid syntax: -op %s\n", op);
335 XSEGLOG2(&lc, E, "I/O pattern needs to be supplied\n");
338 r = read_pattern(pattern);
340 XSEGLOG2(&lc, E, "Invalid syntax: --pattern %s\n", pattern);
343 SET_FLAG(PATTERN, prefs->flags, r);
346 strcpy(verify, "no");
347 r = read_verify(verify);
349 XSEGLOG2(&lc, E, "Invalid syntax: --verify %s\n", verify);
352 SET_FLAG(VERIFY, prefs->flags, r);
354 //Default iodepth value is 1
358 prefs->iodepth = iodepth;
360 /**************************\
361 * Check timer parameters *
362 \**************************/
364 //Most of the times, not all timers need to be used.
365 //We can choose which timers will be used by adjusting the "insanity"
366 //level of the benchmark i.e. the obscurity of code paths (get request,
367 //submit request) that will be timed.
369 strcpy(insanity, "sane");
371 r = read_insanity(insanity);
373 XSEGLOG2(&lc, E, "Invalid syntax: --insanity %s\n", insanity);
376 SET_FLAG(INSANITY, prefs->flags, r);
378 /*****************************\
379 * Check I/O size parameters *
380 \*****************************/
382 //Block size (bs): Defaults to 4K.
383 //It must be a number followed by one of these characters:
385 //If not, it will be considered as size in bytes.
386 //Must be integer multiple of segment's page size (typically 4k).
388 strcpy(block_size,"4k");
390 prefs->bs = str2num(block_size);
392 XSEGLOG2(&lc, E, "Invalid syntax: -bs %s\n", block_size);
394 } else if (prefs->bs % xseg_page_size) {
395 XSEGLOG2(&lc, E, "Misaligned block size: %s\n", block_size);
399 //Object size (os): Defaults to 4M.
400 //Must have the same format as "block size"
401 //Must be integer multiple of "block size"
403 strcpy(object_size,"4M");
405 prefs->os = str2num(object_size);
407 XSEGLOG2(&lc, E, "Invalid syntax: -os %s\n", object_size);
409 } else if (prefs->os % prefs->bs) {
410 XSEGLOG2(&lc, E, "Misaligned object size: %s\n", object_size);
414 //Total objects (to) or total I/O size (ts).
415 //Must have the same format as "block size"
416 //They are mutually exclusive
417 if (total_objects[0] && total_size[0]) {
418 XSEGLOG2(&lc, E, "Total objects and total size are "
419 "mutually exclusive\n");
421 } else if (total_objects[0]) {
422 prefs->to = str2num(total_objects);
424 XSEGLOG2(&lc, E, "Invalid syntax: -to %s\n",
428 //In this case, the maximum number of requests is the total
429 //number of objects we will handle
430 prefs->status->max = prefs->to;
431 } else if (total_size[0]) {
432 if (prefs->op != X_READ && prefs->op != X_WRITE) {
433 XSEGLOG2(&lc, E, "Total objects must be supplied "
434 "(required by -op %s)\n", op);
437 prefs->ts = str2num(total_size);
439 XSEGLOG2(&lc, E, "Invalid syntax: -ts %s\n", total_size);
441 } else if (prefs->ts % prefs->bs) {
442 XSEGLOG2(&lc, E, "Misaligned total I/O size: %s\n", total_size);
445 //In this case, the maximum number of requests is the number of
446 //blocks we need to cover the total I/O size
447 prefs->status->max = prefs->ts / prefs->bs;
448 } else if (!objname[0]) {
449 XSEGLOG2(&lc, E, "Total objects or total size must be supplied\n");
454 * Enforce --objname restrictions here.
458 XSEGLOG2(&lc, E, "-to %s: Total objects are restricted "
459 "to 1 due to --objname %s\n",
460 total_objects, objname);
462 } else if (prefs->ts > prefs->os) {
463 XSEGLOG2(&lc, E, "-ts %s: Total size can't be larger "
464 "than object size (%s) due to "
466 total_size, object_size, objname);
468 } else if (prefs->op == X_READ || prefs->op == X_WRITE) {
469 prefs->ts = prefs->os;
470 prefs->status->max = prefs->ts / prefs->bs;
473 prefs->status->max = 1;
477 if (prefs->status->max == 1)
478 SET_FLAG(PATTERN, prefs->flags, PATTERN_SEQ);
480 /*************************\
481 * Check port parameters *
482 \*************************/
485 XSEGLOG2(&lc, E, "Target port must be supplied\n");
489 prefs->src_port = peer->portno_start; //TODO: allow user to change this
490 prefs->dst_port = (xport) dst_port;
492 /*********************************\
493 * Create timers for all metrics *
494 \*********************************/
496 if (init_timer(&prefs->total_tm, INSANITY_SANE))
498 if (init_timer(&prefs->sub_tm, INSANITY_MANIC))
500 if (init_timer(&prefs->get_tm, INSANITY_PARANOID))
502 if (init_timer(&prefs->rec_tm, INSANITY_ECCENTRIC))
505 /***********************\
506 * Initialize the LFSR *
507 \***********************/
509 seed_max = pow(10, obv->seedlen + 1) - 1;
513 } else if (validate_seed(prefs, seed)) {
514 XSEGLOG2(&lc, E, "--seed %lu: Seed larger than %lu. Only its "
515 "first %d digits will be used",
516 seed, seed_max, obv->seedlen);
522 seed = rand() % seed_max + 1;
524 if (GET_FLAG(PATTERN, prefs->flags) == PATTERN_RAND) {
525 prefs->lfsr = malloc(sizeof(struct bench_lfsr));
531 r = lfsr_init(prefs->lfsr, prefs->status->max,
538 XSEGLOG2(&lc, E, "LFSR could not be initialized.\n");
544 /*********************************\
545 * Miscellaneous initializations *
546 \*********************************/
548 /* The request cap must be enforced only after the LFSR is initialized */
549 if (request_cap[0]) {
550 rc = str2num(request_cap);
552 XSEGLOG2(&lc, E, "Invalid syntax: -rc %s\n", request_cap);
554 } else if (rc > prefs->status->max) {
555 XSEGLOG2(&lc, E, "Request cap exceeds current request total.\n");
558 prefs->status->max = rc;
561 /**********************************\
562 * Progress report initialization *
563 \**********************************/
565 /* Progress report is on by default */
567 strcpy(progress, "yes");
568 r = read_progress(progress);
570 XSEGLOG2(&lc, E, "Invalid syntax: --progress %s\n", progress);
573 SET_FLAG(PROGRESS, prefs->flags, r);
576 * Progress report interval definition or progress type definition makes
577 * no sense with disabled progress reports.
579 if ((GET_FLAG(PROGRESS, prefs->flags) == PROGRESS_NO) &&
580 (pinterval[0] || ptype[0])) {
581 XSEGLOG2(&lc, E, "Cannot define progress interval or progress "
582 "type without enabling progress report\n");
586 if (GET_FLAG(PROGRESS, prefs->flags) != PROGRESS_NO) {
587 /* Progress type is 'both' by default */
589 strcpy(ptype, "both");
590 prefs->rep->type = read_progress_type(ptype);
591 if (prefs->rep->type < 0) {
592 XSEGLOG2(&lc, E, "Invalid syntax: --ptype %s\n", ptype);
595 prefs->rep->lines = calculate_report_lines(prefs);
598 if (GET_FLAG(PROGRESS, prefs->flags) != PROGRESS_NO) {
599 /* By default, we print every 5% */
601 strcpy(pinterval, "5%");
602 prefs->rep->interval = read_interval(prefs, pinterval);
603 if (prefs->rep->interval == 0) {
604 XSEGLOG2(&lc, E, "Invalid syntax: --pinterval %s\n",
610 /* Pinging the target peer is on by default */
615 XSEGLOG2(&lc, E, "Invalid syntax: --ping %s\n", ping);
618 SET_FLAG(PING, prefs->flags, r);
621 peer->peerd_loop = bench_peerd_loop;
622 peer->priv = (void *) prefs;
625 XSEGLOG2(&lc, I, "Seed is %u, prefix is %s",
626 obv->seed, obv->prefix);
628 XSEGLOG2(&lc, I, "Seed is %u, object name is %s",
629 obv->seed, obv->name);
638 free(prefs->total_tm);
644 for (; j >= 0; j--) {
645 free(peer->peer_reqs[j].priv);
647 progress_report_fail:
650 free(prefs->objvars);
659 static int send_request(struct peerd *peer, struct bench *prefs)
661 struct xseg_request *req;
662 struct xseg *xseg = peer->xseg;
664 struct object_vars *obv = prefs->objvars;
665 xport srcport = prefs->src_port;
666 xport dstport = prefs->dst_port;
671 uint64_t size = prefs->bs;
674 //srcport and dstport must already be provided by the user.
675 //returns struct xseg_request with basic initializations
676 XSEGLOG2(&lc, D, "Get new request\n");
677 timer_start(prefs, prefs->get_tm);
678 req = xseg_get_request(xseg, srcport, dstport, X_ALLOC);
680 XSEGLOG2(&lc, W, "Cannot get request\n");
683 timer_stop(prefs, prefs->get_tm, NULL);
686 * Allocate enough space for the data and the target's name.
687 * Also, allocate one extra byte to prevent buffer overflow due to the
688 * obligatory null termination of snprint(). This extra byte will not be
689 * counted as part of the target's name.
691 XSEGLOG2(&lc, D, "Prepare new request\n");
692 r = xseg_prep_request(xseg, req, obv->namelen + 1, size);
694 XSEGLOG2(&lc, W, "Cannot prepare request! (%lu, %llu)\n",
695 obv->namelen + 1, (unsigned long long)size);
696 goto put_xseg_request;
700 //Determine what the next target/chunk will be, based on I/O pattern
701 new = determine_next(prefs);
703 XSEGLOG2(&lc, I, "Our new request is %lu\n", new);
704 obv->objnum = __get_object(prefs, new);
705 create_target(prefs, req);
707 if (prefs->op == X_WRITE || prefs->op == X_READ) {
709 //Calculate the chunk's offset inside the object
710 req->offset = calculate_offset(prefs, new);
711 XSEGLOG2(&lc, D, "Offset of request %lu is %lu\n", new, req->offset);
713 if (prefs->op == X_WRITE)
714 create_chunk(prefs, req, new);
717 XSEGLOG2(&lc, D, "Allocate peer request\n");
718 pr = alloc_peer_req(peer);
720 XSEGLOG2(&lc, W, "Cannot allocate peer request (%ld remaining)\n",
721 peer->nr_ops - xq_count(&peer->free_reqs));
722 goto put_xseg_request;
725 pr->portno = srcport;
728 //XSEGLOG2(&lc, D, "Set request data\n");
729 r = xseg_set_req_data(xseg, req, pr);
731 XSEGLOG2(&lc, W, "Cannot set request data\n");
732 goto put_peer_request;
736 * Start measuring receive time.
737 * When we receive a request, we need to have its submission time to
738 * measure elapsed time. Thus, we copy its submission time to pr->priv.
739 * QUESTION: Is this the fastest way?
741 timer_start(prefs, prefs->rec_tm);
742 if (prefs->rec_tm->insanity <= GET_FLAG(INSANITY, prefs->flags)) {
743 ts = (struct timespec *)pr->priv;
744 ts->tv_sec = prefs->rec_tm->start_time.tv_sec;
745 ts->tv_nsec = prefs->rec_tm->start_time.tv_nsec;
748 //Submit the request from the source port to the target port
749 XSEGLOG2(&lc, D, "Submit request %lu\n", new);
750 timer_start(prefs, prefs->sub_tm);
751 p = xseg_submit(xseg, req, srcport, X_ALLOC);
753 XSEGLOG2(&lc, W, "Cannot submit request\n");
754 goto put_peer_request;
756 prefs->status->submitted++;
757 timer_stop(prefs, prefs->sub_tm, NULL);
759 //Send SIGIO to the process that has bound this port to inform that
761 r = xseg_signal(xseg, p);
763 // XSEGLOG2(&lc, W, "Cannot signal destination peer (reason %d)\n", r);
768 free_peer_req(peer, pr);
770 if (xseg_put_request(xseg, req, srcport))
771 XSEGLOG2(&lc, W, "Cannot put request\n");
775 static int send_ping_request(struct peerd *peer, struct bench *prefs)
777 struct xseg_request *req;
778 struct xseg *xseg = peer->xseg;
780 xport srcport = prefs->src_port;
781 xport dstport = prefs->dst_port;
785 XSEGLOG2(&lc, I, "Sending ping request...");
786 //srcport and dstport must already be provided by the user.
787 //returns struct xseg_request with basic initializations
788 XSEGLOG2(&lc, D, "Get new request\n");
789 req = xseg_get_request(xseg, srcport, dstport, X_ALLOC);
791 XSEGLOG2(&lc, W, "Cannot get request\n");
796 XSEGLOG2(&lc, D, "Allocate peer request\n");
797 pr = alloc_peer_req(peer);
799 XSEGLOG2(&lc, W, "Cannot allocate peer request (%ld remaining)\n",
800 peer->nr_ops - xq_count(&peer->free_reqs));
801 goto put_xseg_request;
804 pr->portno = srcport;
807 r = xseg_set_req_data(xseg, req, pr);
809 XSEGLOG2(&lc, W, "Cannot set request data\n");
810 goto put_peer_request;
813 //Submit the request from the source port to the target port
814 XSEGLOG2(&lc, D, "Submit ping request");
815 p = xseg_submit(xseg, req, srcport, X_ALLOC);
817 XSEGLOG2(&lc, W, "Cannot submit request\n");
818 goto put_peer_request;
820 timer_stop(prefs, prefs->sub_tm, NULL);
822 //Send SIGIO to the process that has bound this port to inform that
824 r = xseg_signal(xseg, p);
826 // XSEGLOG2(&lc, W, "Cannot signal destination peer (reason %d)\n", r);
831 free_peer_req(peer, pr);
833 if (xseg_put_request(xseg, req, srcport))
834 XSEGLOG2(&lc, W, "Cannot put request\n");
839 * This function substitutes the default generic_peerd_loop of peer.c.
840 * It's plugged to struct peerd at custom peer's initialisation
842 int bench_peerd_loop(void *arg)
845 struct thread *t = (struct thread *) arg;
846 struct peerd *peer = t->peer;
849 struct peerd *peer = (struct peerd *) arg;
850 char id[4] = {'P','e','e','r'};
852 struct xseg *xseg = peer->xseg;
853 struct bench *prefs = peer->priv;
854 xport portno_start = peer->portno_start;
855 xport portno_end = peer->portno_end;
856 pid_t pid = syscall(SYS_gettid);
857 uint64_t threshold = peer->threshold;
858 threshold /= (1 + portno_end - portno_start);
860 uint64_t next_report = prefs->rep->interval;
864 XSEGLOG2(&lc, I, "%s has tid %u.\n",id, pid);
865 xseg_init_local_signal(xseg, peer->portno_start);
867 if (GET_FLAG(PROGRESS, prefs->flags) != PROGRESS_NO)
868 print_dummy_progress(prefs);
870 /* If no ping is going to be sent, we can begin the benchmark now. */
871 if (GET_FLAG(PING, prefs->flags) == PING_MODE_ON)
872 send_ping_request(peer, prefs);
874 timer_start(prefs, prefs->total_tm);
877 while (!(isTerminate() && all_peer_reqs_free(peer))) {
878 while (CAN_SEND_REQUEST(prefs)) {
879 xseg_cancel_wait(xseg, peer->portno_start);
880 XSEGLOG2(&lc, D, "...because %lu < %lu && %lu < %lu\n",
881 prefs->status->submitted - prefs->status->received,
882 prefs->iodepth, prefs->status->received,
884 XSEGLOG2(&lc, D, "Start sending new request\n");
885 r = send_request(peer, prefs);
889 //Heart of peerd_loop. This loop is common for everyone.
890 for (loops = threshold; loops > 0; loops--) {
892 xseg_prepare_wait(xseg, peer->portno_start);
894 if (CAN_PRINT_PROGRESS(prefs, next_report)) {
895 print_progress(prefs);
896 next_report += prefs->rep->interval;
899 if (check_ports(peer)) {
900 //If an old request has just been acked, the
901 //most sensible thing to do is to immediately
903 if (prefs->status->received < prefs->status->max)
909 XSEGLOG2(&lc, I, "%s goes to sleep\n", id);
910 xseg_wait_signal(xseg, peer->sd, 10000000UL);
911 xseg_cancel_wait(xseg, peer->portno_start);
912 XSEGLOG2(&lc, I, "%s woke up\n", id);
915 XSEGLOG2(&lc, I, "peer->free_reqs = %d, peer->nr_ops = %d\n",
916 xq_count(&peer->free_reqs), peer->nr_ops);
920 void custom_peer_finalize(struct peerd *peer)
922 struct bench *prefs = peer->priv;
923 //TODO: Measure mean time, standard variation
925 timer_stop(prefs, prefs->total_tm, NULL);
927 if (GET_FLAG(PROGRESS, prefs->flags) != PROGRESS_NO)
928 clear_report_lines(prefs->rep->lines);
930 print_req_stats(prefs);
931 print_remaining(prefs);
932 print_total_res(prefs);
934 if (GET_FLAG(INSANITY, prefs->flags) >= prefs->rec_tm->insanity)
935 print_rec_res(prefs);
939 * This is kinda hacky but is reasonable.
940 * During the benchmark, we need to calculate the bandwidth within an
942 * After the benchmark, we need to calculate the total bandwidth. To do
943 * so, we treat the benchmark as one single interval, and that's what
944 * the two lines below do. This way, the same code can aplly to both
947 prefs->total_tm->elapsed_time = prefs->total_tm->sum;
948 prefs->rep->interval = prefs->status->received;
949 print_io_stats(prefs);
955 * handle_received: +1 to our received requests.
956 * Do some sanity checks and then check if request is failed.
957 * If not try to verify the request if asked.
959 static void handle_received(struct peerd *peer, struct peer_req *pr)
961 //FIXME: handle null pointer
962 struct bench *prefs = peer->priv;
963 struct timer *rec = prefs->rec_tm;
967 //This is a serious error, so we must stop
968 XSEGLOG2(&lc, E, "Received peer request with no xseg request");
974 * If we were in ping mode, we can now switch off and start the
977 if (GET_FLAG(PING, prefs->flags) == PING_MODE_ON) {
978 XSEGLOG2(&lc, I, "Ping received. Benchmark can start now.");
979 SET_FLAG(PING, prefs->flags, PING_MODE_OFF);
984 prefs->status->received++;
986 if ((GET_FLAG(INSANITY, prefs->flags) < rec->insanity) && !pr->priv) {
987 XSEGLOG2(&lc, W, "Cannot find submission time of request");
991 timer_stop(prefs, rec, (struct timespec *)pr->priv);
993 if (!(pr->req->state & XS_SERVED))
994 prefs->status->failed++;
995 else if (CAN_VERIFY(prefs) && read_chunk(prefs, pr->req))
996 prefs->status->corrupted++;
999 if (xseg_put_request(peer->xseg, pr->req, pr->portno))
1000 XSEGLOG2(&lc, W, "Cannot put xseg request\n");
1002 free_peer_req(peer, pr);
1005 timer_start(prefs, prefs->total_tm);
1008 int dispatch(struct peerd *peer, struct peer_req *pr, struct xseg_request *req,
1009 enum dispatch_reason reason)
1012 case dispatch_accept:
1013 //This is wrong, benchmarking peer should not accept requests,
1014 //only receive them.
1015 XSEGLOG2(&lc, W, "Bench peer should not accept requests\n");
1018 case dispatch_receive:
1019 handle_received(peer, pr);