]>
Commit | Line | Data |
---|---|---|
302ef151 BB |
1 | /*****************************************************************************\ |
2 | * ZPIOS is a heavily modified version of the original PIOS test code. | |
3 | * It is designed to have the test code running in the Linux kernel | |
4 | * against ZFS while still being flexibly controled from user space. | |
5 | * | |
6 | * Copyright (C) 2008-2010 Lawrence Livermore National Security, LLC. | |
7 | * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). | |
8 | * Written by Brian Behlendorf <behlendorf1@llnl.gov>. | |
9 | * LLNL-CODE-403049 | |
10 | * | |
11 | * Original PIOS Test Code | |
12 | * Copyright (C) 2004 Cluster File Systems, Inc. | |
13 | * Written by Peter Braam <braam@clusterfs.com> | |
14 | * Atul Vidwansa <atul@clusterfs.com> | |
15 | * Milind Dumbare <milind@clusterfs.com> | |
16 | * | |
17 | * This file is part of ZFS on Linux. | |
18 | * For details, see <http://github.com/behlendorf/zfs/>. | |
19 | * | |
20 | * ZPIOS is free software; you can redistribute it and/or modify it | |
21 | * under the terms of the GNU General Public License as published by the | |
22 | * Free Software Foundation; either version 2 of the License, or (at your | |
23 | * option) any later version. | |
24 | * | |
25 | * ZPIOS is distributed in the hope that it will be useful, but WITHOUT | |
26 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
27 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
28 | * for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License along | |
31 | * with ZPIOS. If not, see <http://www.gnu.org/licenses/>. | |
32 | \*****************************************************************************/ | |
33 | ||
34 | #include <stdlib.h> | |
35 | #include <stdio.h> | |
36 | #include <string.h> | |
37 | #include <errno.h> | |
38 | #include <getopt.h> | |
39 | #include <assert.h> | |
40 | #include <fcntl.h> | |
41 | #include <unistd.h> | |
42 | #include <sys/ioctl.h> | |
43 | #include "zpios.h" | |
44 | ||
45 | static const char short_opt[] = "t:l:h:e:n:i:j:k:o:m:q:r:c:a:b:g:s:A:B:C:" | |
46 | "L:p:M:xP:R:G:I:N:T:VzOfHv?"; | |
47 | static const struct option long_opt[] = { | |
48 | {"threadcount", required_argument, 0, 't' }, | |
49 | {"threadcount_low", required_argument, 0, 'l' }, | |
50 | {"threadcount_high", required_argument, 0, 'h' }, | |
51 | {"threadcount_incr", required_argument, 0, 'e' }, | |
52 | {"regioncount", required_argument, 0, 'n' }, | |
53 | {"regioncount_low", required_argument, 0, 'i' }, | |
54 | {"regioncount_high", required_argument, 0, 'j' }, | |
55 | {"regioncount_incr", required_argument, 0, 'k' }, | |
56 | {"offset", required_argument, 0, 'o' }, | |
57 | {"offset_low", required_argument, 0, 'm' }, | |
58 | {"offset_high", required_argument, 0, 'q' }, | |
59 | {"offset_incr", required_argument, 0, 'r' }, | |
60 | {"chunksize", required_argument, 0, 'c' }, | |
61 | {"chunksize_low", required_argument, 0, 'a' }, | |
62 | {"chunksize_high", required_argument, 0, 'b' }, | |
63 | {"chunksize_incr", required_argument, 0, 'g' }, | |
64 | {"regionsize", required_argument, 0, 's' }, | |
65 | {"regionsize_low", required_argument, 0, 'A' }, | |
66 | {"regionsize_high", required_argument, 0, 'B' }, | |
67 | {"regionsize_incr", required_argument, 0, 'C' }, | |
68 | {"load", required_argument, 0, 'L' }, | |
69 | {"pool", required_argument, 0, 'p' }, | |
70 | {"name", required_argument, 0, 'M' }, | |
71 | {"cleanup", no_argument, 0, 'x' }, | |
72 | {"prerun", required_argument, 0, 'P' }, | |
73 | {"postrun", required_argument, 0, 'R' }, | |
74 | {"log", required_argument, 0, 'G' }, | |
75 | {"regionnoise", required_argument, 0, 'I' }, | |
76 | {"chunknoise", required_argument, 0, 'N' }, | |
77 | {"threaddelay", required_argument, 0, 'T' }, | |
78 | {"verify", no_argument, 0, 'V' }, | |
79 | {"zerocopy", no_argument, 0, 'z' }, | |
80 | {"nowait", no_argument, 0, 'O' }, | |
81 | {"noprefetch", no_argument, 0, 'f' }, | |
82 | {"human-readable", no_argument, 0, 'H' }, | |
83 | {"verbose", no_argument, 0, 'v' }, | |
84 | {"help", no_argument, 0, '?' }, | |
85 | { 0, 0, 0, 0 }, | |
86 | }; | |
87 | ||
88 | static int zpiosctl_fd; /* Control file descriptor */ | |
89 | static char zpios_version[VERSION_SIZE]; /* Kernel version string */ | |
90 | static char *zpios_buffer = NULL; /* Scratch space area */ | |
91 | static int zpios_buffer_size = 0; /* Scratch space size */ | |
92 | ||
93 | static int | |
94 | usage(void) | |
95 | { | |
96 | fprintf(stderr, "Usage: zpios\n"); | |
97 | fprintf(stderr, | |
98 | " --threadcount -t =values\n" | |
99 | " --threadcount_low -l =value\n" | |
100 | " --threadcount_high -h =value\n" | |
101 | " --threadcount_incr -e =value\n" | |
102 | " --regioncount -n =values\n" | |
103 | " --regioncount_low -i =value\n" | |
104 | " --regioncount_high -j =value\n" | |
105 | " --regioncount_incr -k =value\n" | |
106 | " --offset -o =values\n" | |
107 | " --offset_low -m =value\n" | |
108 | " --offset_high -q =value\n" | |
109 | " --offset_incr -r =value\n" | |
110 | " --chunksize -c =values\n" | |
111 | " --chunksize_low -a =value\n" | |
112 | " --chunksize_high -b =value\n" | |
113 | " --chunksize_incr -g =value\n" | |
114 | " --regionsize -s =values\n" | |
115 | " --regionsize_low -A =value\n" | |
116 | " --regionsize_high -B =value\n" | |
117 | " --regionsize_incr -C =value\n" | |
118 | " --load -L =dmuio|ssf|fpp\n" | |
119 | " --pool -p =pool name\n" | |
120 | " --name -M =test name\n" | |
121 | " --cleanup -x\n" | |
122 | " --prerun -P =pre-command\n" | |
123 | " --postrun -R =post-command\n" | |
124 | " --log -G =log directory\n" | |
125 | " --regionnoise -I =shift\n" | |
126 | " --chunknoise -N =bytes\n" | |
127 | " --threaddelay -T =jiffies\n" | |
128 | " --verify -V\n" | |
129 | " --zerocopy -z\n" | |
130 | " --nowait -O\n" | |
131 | " --noprefetch -f\n" | |
132 | " --human-readable -H\n" | |
133 | " --verbose -v =increase verbosity\n" | |
134 | " --help -? =this help\n\n"); | |
135 | ||
136 | return 0; | |
137 | } | |
138 | ||
139 | static void args_fini(cmd_args_t *args) | |
140 | { | |
141 | assert(args != NULL); | |
142 | free(args); | |
143 | } | |
144 | ||
145 | static cmd_args_t * | |
146 | args_init(int argc, char **argv) | |
147 | { | |
148 | cmd_args_t *args; | |
149 | uint32_t fl_th = 0; | |
150 | uint32_t fl_rc = 0; | |
151 | uint32_t fl_of = 0; | |
152 | uint32_t fl_rs = 0; | |
153 | uint32_t fl_cs = 0; | |
154 | int c, rc; | |
155 | ||
156 | if (argc == 1) { | |
157 | usage(); | |
158 | return (cmd_args_t *)NULL; | |
159 | } | |
160 | ||
161 | /* Configure and populate the args structures */ | |
162 | args = malloc(sizeof(*args)); | |
163 | if (args == NULL) | |
164 | return NULL; | |
165 | ||
166 | memset(args, 0, sizeof(*args)); | |
167 | ||
168 | while ((c=getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1) { | |
169 | rc = 0; | |
170 | ||
171 | switch (c) { | |
172 | case 't': /* --thread count */ | |
173 | rc = set_count(REGEX_NUMBERS, REGEX_NUMBERS_COMMA, | |
174 | &args->T, optarg, &fl_th, "threadcount"); | |
175 | break; | |
176 | case 'l': /* --threadcount_low */ | |
177 | rc = set_lhi(REGEX_NUMBERS, &args->T, optarg, | |
178 | FLAG_LOW, &fl_th, "threadcount_low"); | |
179 | break; | |
180 | case 'h': /* --threadcount_high */ | |
181 | rc = set_lhi(REGEX_NUMBERS, &args->T, optarg, | |
182 | FLAG_HIGH, &fl_th, "threadcount_high"); | |
183 | break; | |
184 | case 'e': /* --threadcount_inc */ | |
185 | rc = set_lhi(REGEX_NUMBERS, &args->T, optarg, | |
186 | FLAG_INCR, &fl_th, "threadcount_incr"); | |
187 | break; | |
188 | case 'n': /* --regioncount */ | |
189 | rc = set_count(REGEX_NUMBERS, REGEX_NUMBERS_COMMA, | |
190 | &args->N, optarg, &fl_rc, "regioncount"); | |
191 | break; | |
192 | case 'i': /* --regioncount_low */ | |
193 | rc = set_lhi(REGEX_NUMBERS, &args->N, optarg, | |
194 | FLAG_LOW, &fl_rc, "regioncount_low"); | |
195 | break; | |
196 | case 'j': /* --regioncount_high */ | |
197 | rc = set_lhi(REGEX_NUMBERS, &args->N, optarg, | |
198 | FLAG_HIGH, &fl_rc, "regioncount_high"); | |
199 | break; | |
200 | case 'k': /* --regioncount_inc */ | |
201 | rc = set_lhi(REGEX_NUMBERS, &args->N, optarg, | |
202 | FLAG_INCR, &fl_rc, "regioncount_incr"); | |
203 | break; | |
204 | case 'o': /* --offset */ | |
205 | rc = set_count(REGEX_SIZE, REGEX_SIZE_COMMA, | |
206 | &args->O, optarg, &fl_of, "offset"); | |
207 | break; | |
208 | case 'm': /* --offset_low */ | |
209 | rc = set_lhi(REGEX_SIZE, &args->O, optarg, | |
210 | FLAG_LOW, &fl_of, "offset_low"); | |
211 | break; | |
212 | case 'q': /* --offset_high */ | |
213 | rc = set_lhi(REGEX_SIZE, &args->O, optarg, | |
214 | FLAG_HIGH, &fl_of, "offset_high"); | |
215 | break; | |
216 | case 'r': /* --offset_inc */ | |
217 | rc = set_lhi(REGEX_NUMBERS, &args->O, optarg, | |
218 | FLAG_INCR, &fl_of, "offset_incr"); | |
219 | break; | |
220 | case 'c': /* --chunksize */ | |
221 | rc = set_count(REGEX_SIZE, REGEX_SIZE_COMMA, | |
222 | &args->C, optarg, &fl_cs, "chunksize"); | |
223 | break; | |
224 | case 'a': /* --chunksize_low */ | |
225 | rc = set_lhi(REGEX_SIZE, &args->C, optarg, | |
226 | FLAG_LOW, &fl_cs, "chunksize_low"); | |
227 | break; | |
228 | case 'b': /* --chunksize_high */ | |
229 | rc = set_lhi(REGEX_SIZE, &args->C, optarg, | |
230 | FLAG_HIGH, &fl_cs, "chunksize_high"); | |
231 | break; | |
232 | case 'g': /* --chunksize_inc */ | |
233 | rc = set_lhi(REGEX_NUMBERS, &args->C, optarg, | |
234 | FLAG_INCR, &fl_cs, "chunksize_incr"); | |
235 | break; | |
236 | case 's': /* --regionsize */ | |
237 | rc = set_count(REGEX_SIZE, REGEX_SIZE_COMMA, | |
238 | &args->S, optarg, &fl_rs, "regionsize"); | |
239 | break; | |
240 | case 'A': /* --regionsize_low */ | |
241 | rc = set_lhi(REGEX_SIZE, &args->S, optarg, | |
242 | FLAG_LOW, &fl_rs, "regionsize_low"); | |
243 | break; | |
244 | case 'B': /* --regionsize_high */ | |
245 | rc = set_lhi(REGEX_SIZE, &args->S, optarg, | |
246 | FLAG_HIGH, &fl_rs, "regionsize_high"); | |
247 | break; | |
248 | case 'C': /* --regionsize_inc */ | |
249 | rc = set_lhi(REGEX_NUMBERS, &args->S, optarg, | |
250 | FLAG_INCR, &fl_rs, "regionsize_incr"); | |
251 | break; | |
252 | case 'L': /* --load */ | |
253 | rc = set_load_params(args, optarg); | |
254 | break; | |
255 | case 'p': /* --pool */ | |
256 | args->pool = optarg; | |
257 | break; | |
258 | case 'M': | |
259 | args->name = optarg; | |
260 | break; | |
261 | case 'x': /* --cleanup */ | |
262 | args->flags |= DMU_REMOVE; | |
263 | break; | |
264 | case 'P': /* --prerun */ | |
265 | strncpy(args->pre, optarg, ZPIOS_PATH_SIZE - 1); | |
266 | break; | |
267 | case 'R': /* --postrun */ | |
268 | strncpy(args->post, optarg, ZPIOS_PATH_SIZE - 1); | |
269 | break; | |
270 | case 'G': /* --log */ | |
271 | strncpy(args->log, optarg, ZPIOS_PATH_SIZE - 1); | |
272 | break; | |
273 | case 'I': /* --regionnoise */ | |
274 | rc = set_noise(&args->regionnoise, optarg, "regionnoise"); | |
275 | break; | |
276 | case 'N': /* --chunknoise */ | |
277 | rc = set_noise(&args->chunknoise, optarg, "chunknoise"); | |
278 | break; | |
279 | case 'T': /* --threaddelay */ | |
280 | rc = set_noise(&args->thread_delay, optarg, "threaddelay"); | |
281 | break; | |
282 | case 'V': /* --verify */ | |
283 | args->flags |= DMU_VERIFY; | |
284 | break; | |
285 | case 'z': /* --zerocopy */ | |
286 | args->flags |= (DMU_WRITE_ZC | DMU_READ_ZC); | |
287 | break; | |
288 | case 'O': /* --nowait */ | |
289 | args->flags |= DMU_WRITE_NOWAIT; | |
290 | break; | |
291 | case 'f': /* --noprefetch */ | |
292 | args->flags |= DMU_READ_NOPF; | |
293 | break; | |
294 | case 'H': /* --human-readable */ | |
295 | args->human_readable = 1; | |
296 | break; | |
297 | case 'v': /* --verbose */ | |
298 | args->verbose++; | |
299 | break; | |
300 | case '?': | |
301 | rc = 1; | |
302 | break; | |
303 | default: | |
304 | fprintf(stderr,"Unknown option '%s'\n",argv[optind-1]); | |
305 | rc = EINVAL; | |
306 | break; | |
307 | } | |
308 | ||
309 | if (rc) { | |
310 | usage(); | |
311 | args_fini(args); | |
312 | return NULL; | |
313 | } | |
314 | } | |
315 | ||
316 | check_mutual_exclusive_command_lines(fl_th, "threadcount"); | |
317 | check_mutual_exclusive_command_lines(fl_rc, "regioncount"); | |
318 | check_mutual_exclusive_command_lines(fl_of, "offset"); | |
319 | check_mutual_exclusive_command_lines(fl_rs, "regionsize"); | |
320 | check_mutual_exclusive_command_lines(fl_cs, "chunksize"); | |
321 | ||
322 | if (args->pool == NULL) { | |
323 | fprintf(stderr, "Error: Pool not specificed\n"); | |
324 | usage(); | |
325 | args_fini(args); | |
326 | return NULL; | |
327 | } | |
328 | ||
329 | if ((args->flags & (DMU_WRITE_ZC | DMU_READ_ZC)) && | |
330 | (args->flags & DMU_VERIFY)) { | |
331 | fprintf(stderr, "Error, --zerocopy incompatible --verify, " | |
332 | "used for performance analysis only\n"); | |
333 | usage(); | |
334 | args_fini(args); | |
335 | return NULL; | |
336 | } | |
337 | ||
338 | return args; | |
339 | } | |
340 | ||
341 | static int | |
342 | dev_clear(void) | |
343 | { | |
344 | zpios_cfg_t cfg; | |
345 | int rc; | |
346 | ||
347 | memset(&cfg, 0, sizeof(cfg)); | |
348 | cfg.cfg_magic = ZPIOS_CFG_MAGIC; | |
349 | cfg.cfg_cmd = ZPIOS_CFG_BUFFER_CLEAR; | |
350 | cfg.cfg_arg1 = 0; | |
351 | ||
352 | rc = ioctl(zpiosctl_fd, ZPIOS_CFG, &cfg); | |
353 | if (rc) | |
354 | fprintf(stderr, "Ioctl() error %lu / %d: %d\n", | |
355 | (unsigned long) ZPIOS_CFG, cfg.cfg_cmd, errno); | |
356 | ||
357 | lseek(zpiosctl_fd, 0, SEEK_SET); | |
358 | ||
359 | return rc; | |
360 | } | |
361 | ||
362 | /* Passing a size of zero simply results in querying the current size */ | |
363 | static int | |
364 | dev_size(int size) | |
365 | { | |
366 | zpios_cfg_t cfg; | |
367 | int rc; | |
368 | ||
369 | memset(&cfg, 0, sizeof(cfg)); | |
370 | cfg.cfg_magic = ZPIOS_CFG_MAGIC; | |
371 | cfg.cfg_cmd = ZPIOS_CFG_BUFFER_SIZE; | |
372 | cfg.cfg_arg1 = size; | |
373 | ||
374 | rc = ioctl(zpiosctl_fd, ZPIOS_CFG, &cfg); | |
375 | if (rc) { | |
376 | fprintf(stderr, "Ioctl() error %lu / %d: %d\n", | |
377 | (unsigned long) ZPIOS_CFG, cfg.cfg_cmd, errno); | |
378 | return rc; | |
379 | } | |
380 | ||
381 | return cfg.cfg_rc1; | |
382 | } | |
383 | ||
384 | static void | |
385 | dev_fini(void) | |
386 | { | |
387 | if (zpios_buffer) | |
388 | free(zpios_buffer); | |
389 | ||
390 | if (zpiosctl_fd != -1) { | |
391 | if (close(zpiosctl_fd) == -1) { | |
392 | fprintf(stderr, "Unable to close %s: %d\n", | |
393 | ZPIOS_DEV, errno); | |
394 | } | |
395 | } | |
396 | } | |
397 | ||
398 | static int | |
399 | dev_init(void) | |
400 | { | |
401 | int rc; | |
402 | ||
403 | zpiosctl_fd = open(ZPIOS_DEV, O_RDONLY); | |
404 | if (zpiosctl_fd == -1) { | |
405 | fprintf(stderr, "Unable to open %s: %d\n" | |
406 | "Is the zpios module loaded?\n", ZPIOS_DEV, errno); | |
407 | rc = errno; | |
408 | goto error; | |
409 | } | |
410 | ||
411 | if ((rc = dev_clear())) | |
412 | goto error; | |
413 | ||
414 | if ((rc = dev_size(0)) < 0) | |
415 | goto error; | |
416 | ||
417 | zpios_buffer_size = rc; | |
418 | zpios_buffer = (char *)malloc(zpios_buffer_size); | |
419 | if (zpios_buffer == NULL) { | |
420 | rc = ENOMEM; | |
421 | goto error; | |
422 | } | |
423 | ||
424 | memset(zpios_buffer, 0, zpios_buffer_size); | |
425 | return 0; | |
426 | error: | |
427 | if (zpiosctl_fd != -1) { | |
428 | if (close(zpiosctl_fd) == -1) { | |
429 | fprintf(stderr, "Unable to close %s: %d\n", | |
430 | ZPIOS_DEV, errno); | |
431 | } | |
432 | } | |
433 | ||
434 | return rc; | |
435 | } | |
436 | ||
437 | static int | |
438 | get_next(uint64_t *val, range_repeat_t *range) | |
439 | { | |
440 | /* if low, incr, high is given */ | |
441 | if (range->val_count == 0) { | |
442 | *val = (range->val_low) + | |
443 | (range->val_low * range->next_val / 100); | |
444 | ||
445 | if (*val > range->val_high) | |
446 | return 0; /* No more values, limit exceeded */ | |
447 | ||
448 | if (!range->next_val) | |
449 | range->next_val = range->val_inc_perc; | |
450 | else | |
451 | range->next_val = range->next_val+range->val_inc_perc; | |
452 | ||
453 | return 1; /* more values to come */ | |
454 | ||
455 | /* if only one val is given */ | |
456 | } else if (range->val_count == 1) { | |
457 | if (range->next_val) | |
458 | return 0; /* No more values, we only have one */ | |
459 | ||
460 | *val = range->val[0]; | |
461 | range->next_val = 1; | |
462 | return 1; /* more values to come */ | |
463 | ||
464 | /* if comma separated values are given */ | |
465 | } else if (range->val_count > 1) { | |
466 | if (range->next_val > range->val_count - 1) | |
467 | return 0; /* No more values, limit exceeded */ | |
468 | ||
469 | *val = range->val[range->next_val]; | |
470 | range->next_val++; | |
471 | return 1; /* more values to come */ | |
472 | } | |
473 | ||
474 | return 0; | |
475 | } | |
476 | ||
477 | static int | |
478 | run_one(cmd_args_t *args, uint32_t id, uint32_t T, uint32_t N, | |
479 | uint64_t C, uint64_t S, uint64_t O) | |
480 | { | |
481 | zpios_cmd_t *cmd; | |
482 | int rc, rc2, cmd_size; | |
483 | ||
484 | dev_clear(); | |
485 | ||
486 | cmd_size = sizeof(zpios_cmd_t) + ((T + N + 1) * sizeof(zpios_stats_t)); | |
487 | cmd = (zpios_cmd_t *)malloc(cmd_size); | |
488 | if (cmd == NULL) | |
489 | return ENOMEM; | |
490 | ||
491 | memset(cmd, 0, cmd_size); | |
492 | cmd->cmd_magic = ZPIOS_CMD_MAGIC; | |
493 | strncpy(cmd->cmd_pool, args->pool, ZPIOS_NAME_SIZE - 1); | |
494 | strncpy(cmd->cmd_pre, args->pre, ZPIOS_PATH_SIZE - 1); | |
495 | strncpy(cmd->cmd_post, args->post, ZPIOS_PATH_SIZE - 1); | |
496 | strncpy(cmd->cmd_log, args->log, ZPIOS_PATH_SIZE - 1); | |
497 | cmd->cmd_id = id; | |
498 | cmd->cmd_chunk_size = C; | |
499 | cmd->cmd_thread_count = T; | |
500 | cmd->cmd_region_count = N; | |
501 | cmd->cmd_region_size = S; | |
502 | cmd->cmd_offset = O; | |
503 | cmd->cmd_region_noise = args->regionnoise; | |
504 | cmd->cmd_chunk_noise = args->chunknoise; | |
505 | cmd->cmd_thread_delay = args->thread_delay; | |
506 | cmd->cmd_flags = args->flags; | |
507 | cmd->cmd_data_size = (T + N + 1) * sizeof(zpios_stats_t); | |
508 | ||
509 | rc = ioctl(zpiosctl_fd, ZPIOS_CMD, cmd); | |
510 | if (rc) | |
511 | args->rc = errno; | |
512 | ||
513 | print_stats(args, cmd); | |
514 | ||
515 | if (args->verbose) { | |
516 | rc2 = read(zpiosctl_fd, zpios_buffer, zpios_buffer_size - 1); | |
517 | if (rc2 < 0) { | |
518 | fprintf(stdout, "Error reading results: %d\n", rc2); | |
519 | } else if ((rc2 > 0) && (strlen(zpios_buffer) > 0)) { | |
520 | fprintf(stdout, "\n%s\n", zpios_buffer); | |
521 | fflush(stdout); | |
522 | } | |
523 | } | |
524 | ||
525 | free(cmd); | |
526 | ||
527 | return rc; | |
528 | } | |
529 | ||
530 | static int | |
531 | run_offsets(cmd_args_t *args) | |
532 | { | |
533 | int rc = 0; | |
534 | ||
535 | while (rc == 0 && get_next(&args->current_O, &args->O)) { | |
536 | rc = run_one(args, args->current_id, | |
537 | args->current_T, args->current_N, args->current_C, | |
538 | args->current_S, args->current_O); | |
539 | args->current_id++; | |
540 | } | |
541 | ||
542 | args->O.next_val = 0; | |
543 | return rc; | |
544 | } | |
545 | ||
546 | static int | |
547 | run_region_counts(cmd_args_t *args) | |
548 | { | |
549 | int rc = 0; | |
550 | ||
551 | while (rc == 0 && get_next((uint64_t *)&args->current_N, &args->N)) | |
552 | rc = run_offsets(args); | |
553 | ||
554 | args->N.next_val = 0; | |
555 | return rc; | |
556 | } | |
557 | ||
558 | static int | |
559 | run_region_sizes(cmd_args_t *args) | |
560 | { | |
561 | int rc = 0; | |
562 | ||
563 | while (rc == 0 && get_next(&args->current_S, &args->S)) { | |
564 | if (args->current_S < args->current_C) { | |
565 | fprintf(stderr, "Error: in any run chunksize can " | |
566 | "not be smaller than regionsize.\n"); | |
567 | return EINVAL; | |
568 | } | |
569 | ||
570 | rc = run_region_counts(args); | |
571 | } | |
572 | ||
573 | args->S.next_val = 0; | |
574 | return rc; | |
575 | } | |
576 | ||
577 | static int | |
578 | run_chunk_sizes(cmd_args_t *args) | |
579 | { | |
580 | int rc = 0; | |
581 | ||
582 | while (rc == 0 && get_next(&args->current_C, &args->C)) { | |
583 | rc = run_region_sizes(args); | |
584 | } | |
585 | ||
586 | args->C.next_val = 0; | |
587 | return rc; | |
588 | } | |
589 | ||
590 | static int | |
591 | run_thread_counts(cmd_args_t *args) | |
592 | { | |
593 | int rc = 0; | |
594 | ||
595 | while (rc == 0 && get_next((uint64_t *)&args->current_T, &args->T)) | |
596 | rc = run_chunk_sizes(args); | |
597 | ||
598 | return rc; | |
599 | } | |
600 | ||
601 | int | |
602 | main(int argc, char **argv) | |
603 | { | |
604 | cmd_args_t *args; | |
605 | int rc = 0; | |
606 | ||
607 | /* Argument init and parsing */ | |
608 | if ((args = args_init(argc, argv)) == NULL) { | |
609 | rc = -1; | |
610 | goto out; | |
611 | } | |
612 | ||
613 | /* Device specific init */ | |
614 | if ((rc = dev_init())) | |
615 | goto out; | |
616 | ||
617 | /* Generic kernel version string */ | |
618 | if (args->verbose) | |
619 | fprintf(stdout, "%s", zpios_version); | |
620 | ||
621 | print_stats_header(args); | |
622 | rc = run_thread_counts(args); | |
623 | out: | |
624 | if (args != NULL) | |
625 | args_fini(args); | |
626 | ||
627 | dev_fini(); | |
628 | return rc; | |
629 | } |