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.
38 #include <sys/syscall.h>
39 #include <sys/types.h>
41 #include <xseg/xseg.h>
46 #include <bench-xseg.h>
51 /********************\
53 \********************/
55 #define PRINT_SIG(__who, __sig) \
56 fprintf(stdout, "%s (%lu): id %lu, object %lu, offset %lu\n", \
57 #__who, (uint64_t)(__sig), \
58 ((struct signature *)__sig)->id, \
59 ((struct signature *)__sig)->object, \
60 ((struct signature *)__sig)->offset);
62 __attribute__ ((unused))
63 void inspect_obv(struct object_vars *obv)
65 XSEGLOG2(&lc, D, "Struct object vars:\n"
67 "\tprefix: %s (%d),\n"
70 obv->name, obv->namelen, obv->prefix, obv->prefixlen,
71 obv->seed, obv->seedlen,
72 obv->objnum, obv->objnumlen);
75 /******************************\
76 * Static miscellaneous tools *
77 \******************************/
79 static inline uint64_t __get_object_from_name(struct object_vars *obv,
82 /* In case of --objname switch */
86 /* Keep only the object number */
87 return atol(name + obv->namelen - obv->objnumlen);
90 static inline int __snap_to_bound8(uint64_t space)
92 return space > 8 ? 8 : space;
95 static inline void __write_sig(struct bench_lfsr *sg, uint64_t *d, uint64_t s,
102 /* Write random numbers (based on global_id) every 24 bytes */
103 /* TODO: Should we use memcpy? */
104 for (i = pos; i < (s / 8) - (3 - pos); i += 3)
105 *(d + i) = lfsr_next(sg);
107 /* special care for last chunk */
108 last_val = lfsr_next(sg);
109 space_left = s - (i * 8);
110 memcpy(d + i, &last_val, __snap_to_bound8(space_left));
113 static inline int __read_sig(struct bench_lfsr *sg, uint64_t *d, uint64_t s,
120 /* TODO: Should we use memcmp? */
121 for (i = pos; i < (s / 8) - (3 - pos); i += 3) {
122 if (*(d + i) != lfsr_next(sg))
125 /* special care for last chunk */
126 last_val = lfsr_next(sg);
127 space_left = s - (i * 8);
128 if (memcmp(d + i, &last_val, __snap_to_bound8(space_left)))
135 * ***********************************************
136 * `create_chunk` handles 3 identifiers:
137 * 1. The benchmark's global_id
138 * 2. The object's number
139 * 3. The chunk offset in the object
141 * ************************************************
142 * `readwrite_chunk_full` takes the above 3 identifiers and feeds them as seeds
143 * in 63-bit LFSRs. The numbers generated are written consecutively in chunk's
144 * memory range. For example, for a 72-byte chunk:
146 * || 1 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 ||
147 * ^ 8 16 24 32 40 48 56 64 ^
152 * 1,2,3 differ between each iteration
154 * **************************************************
155 * `_create_chunk_meta` simply writes the above 3 ids in the start and end of
156 * the chunk's memory range, so it should be much faster (but less safe)
158 * **************************************************
159 * In both cases, special care is taken not to exceed the chunk's memory range.
160 * Also, the bare minimum chunk to verify should be 48 bytes. This limit is set
161 * by readwrite_chunk_meta, which expects to write in a memory at least this
164 * **************************************************
165 * Note: The diagram above also represents the x86_64's endianness.
166 * Endianness must be taken into careful consideration when examining a memory
169 static int readwrite_chunk_full(struct bench *prefs, struct xseg_request *req)
171 struct bench_lfsr id_lfsr;
172 struct bench_lfsr obj_lfsr;
173 struct bench_lfsr off_lfsr;
174 struct xseg *xseg = prefs->peer->xseg;
175 uint64_t id = prefs->objvars->seed;
176 uint64_t object = prefs->objvars->objnum;
177 uint64_t *d = (uint64_t *)xseg_get_data(xseg, req);
178 uint64_t s = req->size;
180 /* Create 63-bit LFSRs */
181 lfsr_init(&id_lfsr, 0x7FFFFFFFFFFFFFFF, id, 0);
182 lfsr_init(&obj_lfsr, 0x7FFFFFFFFFFFFFFF, object, 0);
183 lfsr_init(&off_lfsr, 0x7FFFFFFFFFFFFFFF, req->offset, 0);
185 if (s < sizeof(struct signature)) {
186 XSEGLOG2(&lc, E, "Too small chunk size (%lu butes). Leaving.", s);
191 * Every write operation has its read counterpart which, if it finds any
192 * corruption, returns 1
195 if (req->op == X_WRITE) {
196 __write_sig(&id_lfsr, d, s, 0);
197 __write_sig(&obj_lfsr, d, s, 1);
198 __write_sig(&off_lfsr, d, s, 2);
200 if (__read_sig(&id_lfsr, d, s, 0))
202 if (__read_sig(&obj_lfsr, d, s, 1))
204 if(__read_sig(&off_lfsr, d, s, 2))
211 static int readwrite_chunk_meta(struct bench *prefs, struct xseg_request *req)
213 struct xseg *xseg = prefs->peer->xseg;
214 struct signature sig;
215 uint64_t id = prefs->objvars->seed;
216 uint64_t object = prefs->objvars->objnum;
217 char *d = xseg_get_data(xseg, req);
218 uint64_t s = req->size;
219 int sig_s = sizeof(struct signature);
224 sig.offset = req->offset;
227 XSEGLOG2(&lc, E, "Too small chunk size (%lu butes). "
232 //PRINT_SIG(expected, (&sig));
233 /* Read/Write chunk signature both at its start and at its end */
234 if (req->op == X_WRITE) {
235 memcpy(d, &sig, sig_s);
236 memcpy(d + s - sig_s, &sig, sig_s);
238 if (memcmp(d, &sig, sig_s))
240 else if (memcmp(d + s - sig_s, &sig, sig_s))
243 //PRINT_SIG(start, d);
244 //PRINT_SIG(end, (d + s - sig_s));
249 * We want these functions to be as fast as possible in case we haven't asked
252 void create_chunk(struct bench *prefs, struct xseg_request *req, uint64_t new)
256 verify = GET_FLAG(VERIFY, prefs->flags);
261 readwrite_chunk_meta(prefs, req);
264 readwrite_chunk_full(prefs, req);
267 XSEGLOG2(&lc, W, "Unexpected verification mode: %d\n",
272 int read_chunk(struct bench *prefs, struct xseg_request *req)
274 struct xseg *xseg = prefs->peer->xseg;
275 struct object_vars *obv = prefs->objvars;
280 verify = GET_FLAG(VERIFY, prefs->flags);
285 target = xseg_get_target(xseg, req);
286 obv->objnum = __get_object_from_name(obv, target);
287 r = readwrite_chunk_meta(prefs, req);
290 target = xseg_get_target(xseg, req);
291 obv->objnum = __get_object_from_name(obv, target);
292 r = readwrite_chunk_full(prefs, req);
295 XSEGLOG2(&lc, W, "Unexpected verification mode: %d\n",