]> git.proxmox.com Git - mirror_zfs.git/blame - cmd/zpios/zpios_util.c
cstyle: Resolve C style issues
[mirror_zfs.git] / cmd / zpios / zpios_util.c
CommitLineData
d1d7e268 1/*
302ef151
BB
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.
92db59ca 18 * For details, see <http://zfsonlinux.org/>.
302ef151
BB
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/>.
d1d7e268 32 */
302ef151
BB
33
34#include <stdlib.h>
35#include <stdio.h>
36#include <string.h>
37#include <errno.h>
38#include <assert.h>
39#include <regex.h>
40#include "zpios.h"
41
42/* extracts an unsigned int (64) and K,M,G,T from the string */
43/* and returns a 64 bit value converted to the proper units */
44static int
45kmgt_to_uint64(const char *str, uint64_t *val)
46{
47 char *endptr;
48 int rc = 0;
49
50 *val = strtoll(str, &endptr, 0);
51 if ((str == endptr) && (*val == 0))
d1d7e268 52 return (EINVAL);
302ef151
BB
53
54 switch (endptr[0]) {
55 case 'k': case 'K':
56 *val = (*val) << 10;
57 break;
58 case 'm': case 'M':
59 *val = (*val) << 20;
60 break;
61 case 'g': case 'G':
62 *val = (*val) << 30;
63 break;
64 case 't': case 'T':
65 *val = (*val) << 40;
66 break;
67 case '\0':
68 break;
69 default:
70 rc = EINVAL;
71 }
72
d1d7e268 73 return (rc);
302ef151
BB
74}
75
76static char *
77uint64_to_kmgt(char *str, uint64_t val)
78{
79 char postfix[] = "kmgt";
80 int i = -1;
81
82 while ((val >= KB) && (i < 4)) {
83 val = (val >> 10);
84 i++;
85 }
86
87 if (i >= 4)
d1d7e268 88 (void) snprintf(str, KMGT_SIZE-1, "inf");
302ef151 89 else
d1d7e268
MK
90 (void) snprintf(str, KMGT_SIZE-1, "%lu%c", (unsigned long)val,
91 (i == -1) ? '\0' : postfix[i]);
302ef151 92
d1d7e268 93 return (str);
302ef151
BB
94}
95
96static char *
97kmgt_per_sec(char *str, uint64_t v, double t)
98{
99 char postfix[] = "kmgt";
100 double val = ((double)v) / t;
101 int i = -1;
102
103 while ((val >= (double)KB) && (i < 4)) {
104 val /= (double)KB;
105 i++;
106 }
107
108 if (i >= 4)
d1d7e268 109 (void) snprintf(str, KMGT_SIZE-1, "inf");
302ef151 110 else
d1d7e268
MK
111 (void) snprintf(str, KMGT_SIZE-1, "%.2f%c", val,
112 (i == -1) ? '\0' : postfix[i]);
302ef151 113
d1d7e268 114 return (str);
302ef151
BB
115}
116
117static char *
118print_flags(char *str, uint32_t flags)
119{
120 str[0] = (flags & DMU_WRITE) ? 'w' : '-';
121 str[1] = (flags & DMU_READ) ? 'r' : '-';
122 str[2] = (flags & DMU_VERIFY) ? 'v' : '-';
123 str[3] = (flags & DMU_REMOVE) ? 'c' : '-';
124 str[4] = (flags & DMU_FPP) ? 'p' : 's';
125 str[5] = (flags & (DMU_WRITE_ZC | DMU_READ_ZC)) ? 'z' : '-';
126 str[6] = (flags & DMU_WRITE_NOWAIT) ? 'O' : '-';
127 str[7] = '\0';
128
d1d7e268 129 return (str);
302ef151
BB
130}
131
132static int
133regex_match(const char *string, char *pattern)
134{
135 regex_t re = { 0 };
136 int rc;
137
138 rc = regcomp(&re, pattern, REG_EXTENDED | REG_NOSUB | REG_ICASE);
139 if (rc) {
140 fprintf(stderr, "Error: Couldn't do regcomp, %d\n", rc);
d1d7e268 141 return (rc);
302ef151
BB
142 }
143
144 rc = regexec(&re, string, (size_t) 0, NULL, 0);
145 regfree(&re);
146
d1d7e268 147 return (rc);
302ef151
BB
148}
149
150/* fills the pios_range_repeat structure of comma separated values */
151static int
152split_string(const char *optarg, char *pattern, range_repeat_t *range)
153{
154 const char comma[] = ",";
155 char *cp, *token[32];
156 int rc, i = 0;
157
158 if ((rc = regex_match(optarg, pattern)))
d1d7e268 159 return (rc);
302ef151
BB
160
161 cp = strdup(optarg);
162 if (cp == NULL)
d1d7e268 163 return (ENOMEM);
302ef151
BB
164
165 do {
d1d7e268
MK
166 /*
167 * STRTOK(3) Each subsequent call, with a null pointer as the
302ef151
BB
168 * value of the * first argument, starts searching from the
169 * saved pointer and behaves as described above.
170 */
171 token[i] = strtok(cp, comma);
172 cp = NULL;
173 } while ((token[i++] != NULL) && (i < 32));
174
175 range->val_count = i - 1;
176
177 for (i = 0; i < range->val_count; i++)
178 kmgt_to_uint64(token[i], &range->val[i]);
179
180 free(cp);
d1d7e268 181 return (0);
302ef151
BB
182}
183
184int
185set_count(char *pattern1, char *pattern2, range_repeat_t *range,
d1d7e268 186 char *optarg, uint32_t *flags, char *arg)
302ef151
BB
187{
188 if (flags)
189 *flags |= FLAG_SET;
190
191 range->next_val = 0;
192
193 if (regex_match(optarg, pattern1) == 0) {
194 kmgt_to_uint64(optarg, &range->val[0]);
195 range->val_count = 1;
196 } else if (split_string(optarg, pattern2, range) < 0) {
197 fprintf(stderr, "Error: Incorrect pattern for %s, '%s'\n",
d1d7e268
MK
198 arg, optarg);
199 return (EINVAL);
302ef151
BB
200 }
201
d1d7e268 202 return (0);
302ef151
BB
203}
204
d1d7e268
MK
205/*
206 * Validates the value with regular expression and sets low, high, incr
207 * according to value at which flag will be set. Sets the flag after.
208 */
302ef151
BB
209int
210set_lhi(char *pattern, range_repeat_t *range, char *optarg,
d1d7e268 211 int flag, uint32_t *flag_thread, char *arg)
302ef151
BB
212{
213 int rc;
214
215 if ((rc = regex_match(optarg, pattern))) {
216 fprintf(stderr, "Error: Wrong pattern in %s, '%s'\n",
217 arg, optarg);
d1d7e268 218 return (rc);
302ef151
BB
219 }
220
221 switch (flag) {
222 case FLAG_LOW:
223 kmgt_to_uint64(optarg, &range->val_low);
224 break;
225 case FLAG_HIGH:
226 kmgt_to_uint64(optarg, &range->val_high);
227 break;
228 case FLAG_INCR:
229 kmgt_to_uint64(optarg, &range->val_inc_perc);
230 break;
231 default:
232 assert(0);
233 }
234
235 *flag_thread |= flag;
236
d1d7e268 237 return (0);
302ef151
BB
238}
239
240int
241set_noise(uint64_t *noise, char *optarg, char *arg)
242{
243 if (regex_match(optarg, REGEX_NUMBERS) == 0) {
244 kmgt_to_uint64(optarg, noise);
245 } else {
246 fprintf(stderr, "Error: Incorrect pattern for %s\n", arg);
d1d7e268 247 return (EINVAL);
302ef151
BB
248 }
249
d1d7e268 250 return (0);
302ef151
BB
251}
252
253int
254set_load_params(cmd_args_t *args, char *optarg)
255{
256 char *param, *search, comma[] = ",";
257 int rc = 0;
258
259 search = strdup(optarg);
260 if (search == NULL)
d1d7e268 261 return (ENOMEM);
302ef151
BB
262
263 while ((param = strtok(search, comma)) != NULL) {
264 search = NULL;
265
266 if (strcmp("fpp", param) == 0) {
267 args->flags |= DMU_FPP; /* File Per Process/Thread */
268 } else if (strcmp("ssf", param) == 0) {
269 args->flags &= ~DMU_FPP; /* Single Shared File */
270 } else if (strcmp("dmuio", param) == 0) {
271 args->io_type |= DMU_IO;
272 args->flags |= (DMU_WRITE | DMU_READ);
273 } else {
274 fprintf(stderr, "Invalid load: %s\n", param);
275 rc = EINVAL;
276 }
277 }
278
279 free(search);
280
d1d7e268 281 return (rc);
302ef151
BB
282}
283
284
d1d7e268
MK
285/*
286 * Checks the low, high, increment values against the single value for
302ef151 287 * mutual exclusion, for e.g threadcount is mutually exclusive to
d1d7e268
MK
288 * threadcount_low, ..._high, ..._incr
289 */
302ef151
BB
290int
291check_mutual_exclusive_command_lines(uint32_t flag, char *arg)
292{
293 if ((flag & FLAG_SET) && (flag & (FLAG_LOW | FLAG_HIGH | FLAG_INCR))) {
294 fprintf(stderr, "Error: --%s can not be given with --%s_low, "
d1d7e268
MK
295 "--%s_high or --%s_incr.\n", arg, arg, arg, arg);
296 return (0);
302ef151
BB
297 }
298
d1d7e268 299 if ((flag & (FLAG_LOW | FLAG_HIGH | FLAG_INCR)) && !(flag & FLAG_SET)) {
302ef151
BB
300 if (flag != (FLAG_LOW | FLAG_HIGH | FLAG_INCR)) {
301 fprintf(stderr, "Error: One or more values missing "
d1d7e268
MK
302 "from --%s_low, --%s_high, --%s_incr.\n",
303 arg, arg, arg);
304 return (0);
302ef151
BB
305 }
306 }
307
d1d7e268 308 return (1);
302ef151
BB
309}
310
311void
312print_stats_header(cmd_args_t *args)
313{
314 if (args->verbose) {
d1d7e268
MK
315 printf(
316 "status name id\tth-cnt\trg-cnt\trg-sz\t"
317 "ch-sz\toffset\trg-no\tch-no\tth-dly\tflags\ttime\t"
318 "cr-time\trm-time\twr-time\trd-time\twr-data\twr-ch\t"
319 "wr-bw\trd-data\trd-ch\trd-bw\n");
320 printf(
321 "------------------------------------------------"
322 "------------------------------------------------"
323 "------------------------------------------------"
324 "----------------------------------------------\n");
302ef151 325 } else {
d1d7e268
MK
326 printf(
327 "status name id\t"
328 "wr-data\twr-ch\twr-bw\t"
329 "rd-data\trd-ch\trd-bw\n");
330 printf(
331 "-----------------------------------------"
332 "--------------------------------------\n");
302ef151
BB
333 }
334}
335
336static void
337print_stats_human_readable(cmd_args_t *args, zpios_cmd_t *cmd)
338{
339 zpios_stats_t *summary_stats;
340 double t_time, wr_time, rd_time, cr_time, rm_time;
341 char str[KMGT_SIZE];
342
343 if (args->rc)
344 printf("FAIL: %3d ", args->rc);
345 else
346 printf("PASS: ");
347
348 printf("%-12s", args->name ? args->name : ZPIOS_NAME);
d1d7e268 349 printf("%2u\t", cmd->cmd_id);
302ef151
BB
350
351 if (args->verbose) {
d1d7e268
MK
352 printf("%u\t", cmd->cmd_thread_count);
353 printf("%u\t", cmd->cmd_region_count);
354 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_region_size));
355 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_chunk_size));
356 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_offset));
357 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_region_noise));
358 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_chunk_noise));
359 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_thread_delay));
302ef151
BB
360 printf("%s\t", print_flags(str, cmd->cmd_flags));
361 }
362
363 if (args->rc) {
364 printf("\n");
365 return;
366 }
367
368 summary_stats = (zpios_stats_t *)cmd->cmd_data_str;
369 t_time = zpios_timespec_to_double(summary_stats->total_time.delta);
370 wr_time = zpios_timespec_to_double(summary_stats->wr_time.delta);
371 rd_time = zpios_timespec_to_double(summary_stats->rd_time.delta);
372 cr_time = zpios_timespec_to_double(summary_stats->cr_time.delta);
373 rm_time = zpios_timespec_to_double(summary_stats->rm_time.delta);
374
375 if (args->verbose) {
376 printf("%.2f\t", t_time);
377 printf("%.3f\t", cr_time);
378 printf("%.3f\t", rm_time);
379 printf("%.2f\t", wr_time);
380 printf("%.2f\t", rd_time);
381 }
382
d1d7e268
MK
383 printf("%s\t", uint64_to_kmgt(str, summary_stats->wr_data));
384 printf("%s\t", uint64_to_kmgt(str, summary_stats->wr_chunks));
302ef151
BB
385 printf("%s\t", kmgt_per_sec(str, summary_stats->wr_data, wr_time));
386
d1d7e268
MK
387 printf("%s\t", uint64_to_kmgt(str, summary_stats->rd_data));
388 printf("%s\t", uint64_to_kmgt(str, summary_stats->rd_chunks));
302ef151
BB
389 printf("%s\n", kmgt_per_sec(str, summary_stats->rd_data, rd_time));
390 fflush(stdout);
391}
392
393static void
394print_stats_table(cmd_args_t *args, zpios_cmd_t *cmd)
395{
396 zpios_stats_t *summary_stats;
397 double wr_time, rd_time;
398
399 if (args->rc)
400 printf("FAIL: %3d ", args->rc);
401 else
402 printf("PASS: ");
403
404 printf("%-12s", args->name ? args->name : ZPIOS_NAME);
d1d7e268 405 printf("%2u\t", cmd->cmd_id);
302ef151
BB
406
407 if (args->verbose) {
d1d7e268
MK
408 printf("%u\t", cmd->cmd_thread_count);
409 printf("%u\t", cmd->cmd_region_count);
410 printf("%llu\t", (long long unsigned)cmd->cmd_region_size);
411 printf("%llu\t", (long long unsigned)cmd->cmd_chunk_size);
412 printf("%llu\t", (long long unsigned)cmd->cmd_offset);
413 printf("%u\t", cmd->cmd_region_noise);
414 printf("%u\t", cmd->cmd_chunk_noise);
415 printf("%u\t", cmd->cmd_thread_delay);
302ef151
BB
416 printf("0x%x\t", cmd->cmd_flags);
417 }
418
419 if (args->rc) {
420 printf("\n");
421 return;
422 }
423
424 summary_stats = (zpios_stats_t *)cmd->cmd_data_str;
425 wr_time = zpios_timespec_to_double(summary_stats->wr_time.delta);
426 rd_time = zpios_timespec_to_double(summary_stats->rd_time.delta);
427
428 if (args->verbose) {
429 printf("%ld.%02ld\t",
d1d7e268
MK
430 (long)summary_stats->total_time.delta.ts_sec,
431 (long)summary_stats->total_time.delta.ts_nsec);
302ef151 432 printf("%ld.%02ld\t",
d1d7e268
MK
433 (long)summary_stats->cr_time.delta.ts_sec,
434 (long)summary_stats->cr_time.delta.ts_nsec);
302ef151 435 printf("%ld.%02ld\t",
d1d7e268
MK
436 (long)summary_stats->rm_time.delta.ts_sec,
437 (long)summary_stats->rm_time.delta.ts_nsec);
302ef151 438 printf("%ld.%02ld\t",
d1d7e268
MK
439 (long)summary_stats->wr_time.delta.ts_sec,
440 (long)summary_stats->wr_time.delta.ts_nsec);
302ef151 441 printf("%ld.%02ld\t",
d1d7e268
MK
442 (long)summary_stats->rd_time.delta.ts_sec,
443 (long)summary_stats->rd_time.delta.ts_nsec);
302ef151
BB
444 }
445
d1d7e268
MK
446 printf("%lld\t", (long long unsigned)summary_stats->wr_data);
447 printf("%lld\t", (long long unsigned)summary_stats->wr_chunks);
302ef151
BB
448 printf("%.4f\t", (double)summary_stats->wr_data / wr_time);
449
d1d7e268
MK
450 printf("%lld\t", (long long unsigned)summary_stats->rd_data);
451 printf("%lld\t", (long long unsigned)summary_stats->rd_chunks);
302ef151
BB
452 printf("%.4f\n", (double)summary_stats->rd_data / rd_time);
453 fflush(stdout);
454}
455
456void
457print_stats(cmd_args_t *args, zpios_cmd_t *cmd)
458{
459 if (args->human_readable)
460 print_stats_human_readable(args, cmd);
461 else
462 print_stats_table(args, cmd);
463}