c8e8464e5a8837066916d7d6f14f6f0e3067c3f6
[archipelago] / xseg / peers / user / bench-utils.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 #include <bench-xseg.h>
48
49 #include <math.h>
50
51 struct timespec delay = {0, 4000000};
52
53 /*
54  * Convert string to size in bytes.
55  * If syntax is invalid, return 0. Values such as zero and non-integer
56  * multiples of segment's page size should not be accepted.
57  */
58 uint64_t str2num(char *str)
59 {
60         char *unit;
61         uint64_t num;
62
63         num = strtoll(str, &unit, 10);
64         if (strlen(unit) > 1) //Invalid syntax
65                 return 0;
66         else if (strlen(unit) < 1) //Plain number in bytes
67                 return num;
68
69         switch (*unit) {
70                 case 'g':
71                 case 'G':
72                         num *= 1024;
73                 case 'm':
74                 case 'M':
75                         num *= 1024;
76                 case 'k':
77                 case 'K':
78                         num *= 1024;
79                         break;
80                 default:
81                         num = 0;
82         }
83         return num;
84 }
85
86 /*
87  * Converts struct timespec to double (units in nanoseconds)
88  */
89 static double timespec2double(struct timespec num)
90 {
91         return (double) (num.tv_sec * pow(10, 9) + num.tv_nsec);
92 }
93
94 int read_insanity(char *insanity)
95 {
96         if (strcmp(insanity, "sane") == 0)
97                 return TM_SANE;
98         if (strcmp(insanity, "eccentric") == 0)
99                 return TM_ECCENTRIC;
100         if (strcmp(insanity, "manic") == 0)
101                 return TM_MANIC;
102         if (strcmp(insanity, "paranoid") == 0)
103                 return TM_PARANOID;
104         return -1;
105 }
106
107 int read_op(char *op)
108 {
109         if (strcmp(op, "read") == 0)
110                 return X_READ;
111         if (strcmp(op, "write") == 0)
112                 return X_WRITE;
113         if (strcmp(op, "info") == 0)
114                 return X_INFO;
115         if (strcmp(op, "delete") == 0)
116                 return X_DELETE;
117         return -1;
118 }
119
120 int read_pattern(char *pattern)
121 {
122         if (strcmp(pattern, "seq") == 0)
123                 return IO_SEQ;
124         if (strcmp(pattern, "rand") == 0)
125                 return IO_RAND;
126         return -1;
127 }
128
129 /*
130  * Seperates a double number in seconds, msec, usec, nsec
131  * Expects a number in nanoseconds (e.g. a number from timespec2double)
132  */
133 static struct tm_result separate_by_order(double num)
134 {
135         struct tm_result res;
136
137         //The format we expect is the following:
138         //
139         //              |-s-|-ms-|-us-|-ns|
140         //num =  123 456  789  012 . 000000000000
141         res.s = num / pow(10,9);
142         num = fmod(num, pow(10,9));
143         res.ms = num / pow(10,6);
144         num = fmod(num, pow(10,6));
145         res.us = num / 1000;
146         res.ns = fmod(num, 1000);
147
148         return res;
149 }
150
151 void print_stats(struct bench *prefs)
152 {
153         uint64_t remaining;
154
155         printf("\n");
156         printf("Requests total:     %10lu\n", prefs->max_requests);
157         printf("Requests submitted: %10lu\n", prefs->sub_tm->completed);
158         printf("Requests received:  %10lu\n", prefs->rec_tm->completed);
159         printf("\n");
160
161         remaining = prefs->max_requests - prefs->rec_tm->completed;
162         if (remaining)
163                 printf("Requests remaining: %10lu\n", remaining);
164         else
165                 printf("All requests have been served.\n");
166 }
167
168 void print_res(struct bench *prefs, struct timer *tm, char *type)
169 {
170         struct tm_result res;
171         double sum;
172
173         sum = timespec2double(tm->sum);
174         res = separate_by_order(sum);
175
176         printf("\n");
177         printf("              %s\n", type);
178         printf("           ========================\n");
179         printf("             |-s-||-ms-|-us-|-ns-|\n");
180         printf("Total time:   %3u. %03u  %03u  %03u\n",
181                         res.s, res.ms, res.us, res.ns);
182
183         if (!prefs->rec_tm->completed)
184                 return;
185
186         res = separate_by_order(sum / prefs->rec_tm->completed);
187
188         printf("Mean Time:    %3u. %03u  %03u  %03u\n",
189                         res.s, res.ms, res.us, res.ns);
190
191         //TODO: Add std
192 }
193
194 void create_target(struct bench *prefs, struct xseg_request *req,
195                 uint64_t new)
196 {
197         struct xseg *xseg = prefs->peer->xseg;
198         char *req_target;
199
200         req_target = xseg_get_target(xseg, req);
201
202         //For read/write, the target object does not correspond to `new`, which is
203         //actually the chunk number. We need to div this number with the number of
204         //chunks in an object.
205         //FIXME: Make it more elegant
206         if (prefs->op == X_READ || prefs->op == X_WRITE)
207                 new = new / (prefs->os / prefs->bs);
208         snprintf(req_target, TARGETLEN, "%s-%016lu", global_id, new);
209         XSEGLOG2(&lc, D, "Target name of request is %s\n", req_target);
210 }
211
212 void create_chunk(struct bench *prefs, struct xseg_request *req, uint64_t new)
213 {/*
214         struct xseg *xseg = prefs->peer->xseg;
215         char *req_data;
216
217         //TODO: Fill data depening on validation level
218         req_data = xseg_get_data(xseg, req);
219         */
220 }
221
222 uint64_t determine_next(struct bench *prefs)
223 {
224         if ((prefs->flags & (1 << PATTERN_FLAG)) == IO_SEQ)
225                 return prefs->sub_tm->completed;
226         else {
227                 return lfsr_next(prefs->lfsr);
228         }
229 }
230
231 //FIXME: this looks like a hack, handle it more elegantly
232 void create_id(unsigned long seed)
233 {
234         struct timespec timer_seed;
235
236         if (seed != -1) {
237                 global_seed = seed;
238         } else {
239                 clock_gettime(CLOCK_MONOTONIC_RAW, &timer_seed);
240                 global_seed = timer_seed.tv_nsec;
241         }
242         //nanoseconds can't be more than 9 digits
243         snprintf(global_id, IDLEN, "bench-%09lu", global_seed);
244         XSEGLOG2(&lc, I, "Global ID is %s\n", global_id);
245 }