1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Portions Copyright 2008 Denis Cheng
27 */
28
29 %{
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <float.h>
35 #include <limits.h>
36 #include <signal.h>
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <locale.h>
40 #include <sys/utsname.h>
41 #include <sys/statvfs.h>
42 #ifdef HAVE_STDINT_H
43 #include <stdint.h>
44 #endif
45 #include <fcntl.h>
46 #include <sys/mman.h>
47 #include <sys/wait.h>
48 #include "parsertypes.h"
49 #include "filebench.h"
50 #include "utils.h"
51 #include "stats.h"
52 #include "vars.h"
53 #include "eventgen.h"
54 #include "aslr.h"
55 #include "multi_client_sync.h"
56
57 /* yacc and lex externals */
58 extern FILE *yyin;
59 extern int yydebug;
60 extern void yyerror(char *s);
61 extern int yylex(void);
62
63 /* executable name to execute worker processes later */
64 char *execname;
65
66 /* utilities */
67 static cmd_t *alloc_cmd(void);
68 static attr_t *alloc_attr(void);
69 static attr_t *alloc_lvar_attr(var_t *var);
70 static attr_t *get_attr(cmd_t *cmd, int64_t name);
71 static void get_attr_lvars(cmd_t *cmd, flowop_t *flowop);
72 static list_t *alloc_list();
73 static probtabent_t *alloc_probtabent(void);
74 static void add_lvar_to_list(var_t *newlvar, var_t **lvar_list);
75
76 /* Info Commands */
77 static void parser_fileset_list(cmd_t *);
78 static void parser_flowop_list(cmd_t *);
79
80 /* Define Commands */
81 static void parser_proc_define(cmd_t *);
82 static void parser_thread_define(cmd_t *, procflow_t *);
83 static void parser_flowop_define(cmd_t *, threadflow_t *, flowop_t **, int);
84 static void parser_composite_flowop_define(cmd_t *);
85 static void parser_file_define(cmd_t *);
86 static void parser_fileset_define(cmd_t *);
87 static void parser_var_assign_random(char *, cmd_t *);
88 static void parser_var_assign_custom(char *, cmd_t *);
89
90 /* Create Commands */
91 static void parser_fileset_create(cmd_t *);
92
93 /* Run Commands */
94 static void parser_run(cmd_t *cmd);
95 static void parser_run_variable(cmd_t *cmd);
96 static void parser_psrun(cmd_t *cmd);
97
98 /* Shutdown (Quit) Commands */
99 static void parser_filebench_shutdown(cmd_t *cmd);
100
101 /* Other Commands */
102 static void parser_echo(cmd_t *cmd);
103 static void parser_system(cmd_t *cmd);
104 static void parser_eventgen(cmd_t *cmd);
105 static void parser_enable_mc(cmd_t *cmd);
106 static void parser_domultisync(cmd_t *cmd);
107 static void parser_sleep(cmd_t *cmd);
108 static void parser_sleep_variable(cmd_t *cmd);
109 static void parser_version(cmd_t *cmd);
110 static void parser_enable_lathist(cmd_t *cmd);
111
112 %}
113
114 %union {
115 int64_t ival;
116 unsigned char bval;
117 char * sval;
118 avd_t avd;
119 cmd_t *cmd;
120 attr_t *attr;
121 list_t *list;
122 probtabent_t *rndtb;
123 }
124
125 %start commands
126
127 %token FSC_LIST FSC_DEFINE FSC_QUIT FSC_DEBUG FSC_CREATE FSC_SLEEP FSC_SET
128 %token FSC_SYSTEM FSC_EVENTGEN FSC_ECHO FSC_RUN FSC_PSRUN FSC_VERSION FSC_ENABLE
129 %token FSC_DOMULTISYNC
130
131 %token FSV_STRING FSV_VAL_POSINT FSV_VAL_NEGINT FSV_VAL_BOOLEAN FSV_VARIABLE
132 %token FSV_WHITESTRING FSV_RANDUNI FSV_RANDTAB FSV_URAND FSV_RAND48
133
134 %token FSE_FILE FSE_FILES FSE_FILESET FSE_PROC FSE_THREAD FSE_FLOWOP FSE_CVAR
135 %token FSE_RAND FSE_MODE FSE_MULTI
136
137 %token FSK_SEPLST FSK_OPENLST FSK_CLOSELST FSK_OPENPAR FSK_CLOSEPAR FSK_ASSIGN
138 %token FSK_IN FSK_QUOTE
139
140 %token FSA_SIZE FSA_PREALLOC FSA_PARALLOC FSA_PATH FSA_REUSE
141 %token FSA_MEMSIZE FSA_RATE FSA_READONLY FSA_TRUSTTREE
142 %token FSA_IOSIZE FSA_FILENAME FSA_WSS FSA_NAME FSA_RANDOM FSA_INSTANCES
143 %token FSA_DSYNC FSA_TARGET FSA_ITERS FSA_NICE FSA_VALUE FSA_BLOCKING
144 %token FSA_HIGHWATER FSA_DIRECTIO FSA_DIRWIDTH FSA_FD FSA_SRCFD FSA_ROTATEFD
145 %token FSA_ENTRIES FSA_DIRDEPTHRV FSA_DIRGAMMA FSA_USEISM FSA_TYPE
146 %token FSA_LEAFDIRS FSA_INDEXED FSA_RANDTABLE FSA_RANDSRC FSA_ROUND
147 %token FSA_RANDSEED FSA_RANDGAMMA FSA_RANDMEAN FSA_MIN FSA_MAX FSA_MASTER
148 %token FSA_CLIENT FSS_TYPE FSS_SEED FSS_GAMMA FSS_MEAN FSS_MIN FSS_SRC FSS_ROUND
149 %token FSA_LVAR_ASSIGN FSA_ALLDONE FSA_FIRSTDONE FSA_TIMEOUT FSA_LATHIST
150 %token FSA_NOREADAHEAD FSA_IOPRIO FSA_WRITEONLY FSA_PARAMETERS FSA_NOUSESTATS
151
152 %type <ival> FSV_VAL_POSINT FSV_VAL_NEGINT
153 %type <bval> FSV_VAL_BOOLEAN
154 %type <sval> FSV_STRING FSV_WHITESTRING FSV_VARIABLE FSK_ASSIGN
155
156 %type <ival> FSC_DEFINE FSC_SET FSC_RUN FSC_ENABLE FSC_PSRUN
157 %type <ival> FSC_DOMULTISYNC
158 %type <ival> FSE_FILE FSE_FILES FSE_PROC FSE_THREAD FSC_VERSION
159
160 %type <sval> name
161
162 %type <cmd> command run_command list_command psrun_command
163 %type <cmd> proc_define_command files_define_command
164 %type <cmd> flowop_define_command debug_command create_command
165 %type <cmd> sleep_command set_command
166 %type <cmd> system_command flowop_command
167 %type <cmd> eventgen_command quit_command flowop_list thread_list
168 %type <cmd> thread echo_command
169 %type <cmd> version_command enable_command multisync_command
170 %type <cmd> set_variable set_random_variable set_custom_variable set_mode
171
172 %type <attr> fileset_attr_op fileset_attr_ops file_attr_ops file_attr_op p_attr_op t_attr_op p_attr_ops t_attr_ops
173 %type <attr> fo_attr_op fo_attr_ops ev_attr_op ev_attr_ops
174 %type <attr> randvar_attr_op randvar_attr_ops randvar_attr_typop
175 %type <attr> randvar_attr_srcop attr_value
176 %type <attr> comp_lvar_def comp_attr_op comp_attr_ops
177 %type <attr> enable_multi_ops enable_multi_op multisync_op
178 %type <attr> cvar_attr_ops cvar_attr_op
179 %type <list> whitevar_string whitevar_string_list
180 %type <ival> attrs_define_thread attrs_flowop
181 %type <ival> attrs_define_fileset attrs_define_file attrs_define_proc attrs_eventgen attrs_define_comp
182 %type <ival> randvar_attr_name FSA_TYPE randtype_name
183 %type <ival> randsrc_name FSA_RANDSRC em_attr_name
184 %type <ival> FSS_TYPE FSS_SEED FSS_GAMMA FSS_MEAN FSS_MIN FSS_SRC
185 %type <ival> cvar_attr_name
186
187 %type <rndtb> probtabentry_list probtabentry
188 %type <avd> var_int_val
189 %%
190
191 commands: commands command
192 {
193 if ($2->cmd)
194 $2->cmd($2);
195
196 free($2);
197 }
198 | commands error
199 {
200 YYABORT;
201 }
202 |;
203
204 command:
205 proc_define_command
206 | files_define_command
207 | flowop_define_command
208 | debug_command
209 | eventgen_command
210 | create_command
211 | echo_command
212 | list_command
213 | run_command
214 | psrun_command
215 | set_command
216 | quit_command
217 | sleep_command
218 | system_command
219 | version_command
220 | enable_command
221 | multisync_command
222
223 eventgen_command: FSC_EVENTGEN
224 {
225 if (($$ = alloc_cmd()) == NULL)
226 YYERROR;
227 $$->cmd = &parser_eventgen;
228 }
229 | eventgen_command ev_attr_ops
230 {
231 $1->cmd_attr_list = $2;
232 };
233
234 system_command: FSC_SYSTEM whitevar_string_list
235 {
236 if (($$ = alloc_cmd()) == NULL)
237 YYERROR;
238
239 $$->cmd_param_list = $2;
240 $$->cmd = parser_system;
241 };
242
243 echo_command: FSC_ECHO whitevar_string_list
244 {
245 if (($$ = alloc_cmd()) == NULL)
246 YYERROR;
247
248 $$->cmd_param_list = $2;
249 $$->cmd = parser_echo;
250 };
251
252 version_command: FSC_VERSION
253 {
254 if (($$ = alloc_cmd()) == NULL)
255 YYERROR;
256 $$->cmd = parser_version;
257 };
258
259 enable_command: FSC_ENABLE FSE_MULTI enable_multi_ops
260 {
261
262 if (($$ = alloc_cmd()) == NULL)
263 YYERROR;
264
265 $$->cmd = parser_enable_mc;
266 $$->cmd_attr_list = $3;
267 }
268 | FSC_ENABLE FSA_LATHIST
269 {
270 if (($$ = alloc_cmd()) == NULL)
271 YYERROR;
272
273 $$->cmd = parser_enable_lathist;
274 };
275
276 multisync_command: FSC_DOMULTISYNC multisync_op
277 {
278 if (($$ = alloc_cmd()) == NULL)
279 YYERROR;
280
281 $$->cmd = parser_domultisync;
282 $$->cmd_attr_list = $2;
283 }
284
285 whitevar_string: FSK_QUOTE FSV_VARIABLE
286 {
287 if (($$ = alloc_list()) == NULL)
288 YYERROR;
289
290 $$->list_string = avd_str_alloc($2);
291 }
292 | FSK_QUOTE FSV_WHITESTRING
293 {
294 if (($$ = alloc_list()) == NULL)
295 YYERROR;
296
297 $$->list_string = avd_str_alloc($2);
298 };
299
300 whitevar_string_list: whitevar_string FSV_WHITESTRING
301 {
302 list_t *list = NULL;
303 list_t *list_end = NULL;
304
305 /* Add string */
306 if (($$ = alloc_list()) == NULL)
307 YYERROR;
308
309 $$->list_string = avd_str_alloc($2);
310
311 /* Find end of list */
312 for (list = $1; list != NULL;
313 list = list->list_next)
314 list_end = list;
315 list_end->list_next = $$;
316 $$ = $1;
317
318 }| whitevar_string FSV_VARIABLE
319 {
320 list_t *list = NULL;
321 list_t *list_end = NULL;
322
323 /* Add variable */
324 if (($$ = alloc_list()) == NULL)
325 YYERROR;
326
327 $$->list_string = avd_str_alloc($2);
328
329 /* Find end of list */
330 for (list = $1; list != NULL;
331 list = list->list_next)
332 list_end = list;
333 list_end->list_next = $$;
334 $$ = $1;
335 }| whitevar_string_list FSV_WHITESTRING
336 {
337 list_t *list = NULL;
338 list_t *list_end = NULL;
339
340 /* Add string */
341 if (($$ = alloc_list()) == NULL)
342 YYERROR;
343
344 $$->list_string = avd_str_alloc($2);
345
346 /* Find end of list */
347 for (list = $1; list != NULL;
348 list = list->list_next)
349 list_end = list;
350 list_end->list_next = $$;
351 $$ = $1;
352
353 }| whitevar_string_list FSV_VARIABLE
354 {
355 list_t *list = NULL;
356 list_t *list_end = NULL;
357
358 /* Add variable */
359 if (($$ = alloc_list()) == NULL)
360 YYERROR;
361
362 $$->list_string = avd_str_alloc($2);
363
364 /* Find end of list */
365 for (list = $1; list != NULL;
366 list = list->list_next)
367 list_end = list;
368 list_end->list_next = $$;
369 $$ = $1;
370 }| whitevar_string_list FSK_QUOTE
371 {
372 $$ = $1;
373 }| whitevar_string FSK_QUOTE
374 {
375 $$ = $1;
376 };
377
378 list_command: FSC_LIST FSE_FILESET
379 {
380 if (($$ = alloc_cmd()) == NULL)
381 YYERROR;
382 $$->cmd = &parser_fileset_list;
383 }
384 | FSC_LIST FSE_FLOWOP
385 {
386 if (($$ = alloc_cmd()) == NULL)
387 YYERROR;
388 $$->cmd = &parser_flowop_list;
389 };
390
391 debug_command: FSC_DEBUG FSV_VAL_POSINT
392 {
393 if (($$ = alloc_cmd()) == NULL)
394 YYERROR;
395 $$->cmd = NULL;
396 filebench_shm->shm_debug_level = $2;
397 if (filebench_shm->shm_debug_level > 10) {
398 filebench_log(LOG_ERROR, "Debug level set out of range."
399 " Adjusting to 10.");
400 filebench_shm->shm_debug_level = 10;
401 }
402 if (filebench_shm->shm_debug_level > 9)
403 yydebug = 1;
404 };
405
406 set_command: set_variable | set_random_variable | set_custom_variable | set_mode;
407
408 set_variable: FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VAL_POSINT
409 {
410 $$ = alloc_cmd();
411 if (!$$)
412 YYERROR;
413
414 var_assign_integer($2, $4);
415
416 $$->cmd = NULL;
417 }
418 |
419 FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VAL_BOOLEAN
420 {
421 $$ = alloc_cmd();
422 if (!$$)
423 YYERROR;
424
425 var_assign_boolean($2, $4);
426
427 $$->cmd = NULL;
428 }
429 | FSC_SET FSV_VARIABLE FSK_ASSIGN FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
430 {
431 $$ = alloc_cmd();
432 if (!$$)
433 YYERROR;
434
435 var_assign_string($2, $5);
436
437 $$->cmd = NULL;
438 }
439 | FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_STRING
440 {
441 $$ = alloc_cmd();
442 if (!$$)
443 YYERROR;
444
445 var_assign_string($2, $4);
446
447 $$->cmd = NULL;
448 };
449
450 set_random_variable: FSC_SET FSV_VARIABLE FSK_ASSIGN FSE_RAND FSK_OPENPAR randvar_attr_ops FSK_CLOSEPAR
451 {
452 $$ = alloc_cmd();
453 if (!$$)
454 YYERROR;
455
456 $$->cmd_attr_list = $6;
457 $$->cmd = NULL;
458
459 parser_var_assign_random($2, $$);
460 }
461
462 set_custom_variable: FSC_SET FSV_VARIABLE FSK_ASSIGN FSE_CVAR FSK_OPENPAR cvar_attr_ops FSK_CLOSEPAR
463 {
464 $$ = alloc_cmd();
465 if (!$$)
466 YYERROR;
467
468 $$->cmd_attr_list = $6;
469 $$->cmd = NULL;
470
471 parser_var_assign_custom($2, $$);
472 };
473
474 set_mode: FSC_SET FSE_MODE FSC_QUIT FSA_TIMEOUT
475 {
476 $$ = alloc_cmd();
477 if (!$$)
478 YYERROR;
479
480 filebench_shm->shm_rmode = FILEBENCH_MODE_TIMEOUT;
481
482 $$->cmd = NULL;
483 }
484 | FSC_SET FSE_MODE FSC_QUIT FSA_ALLDONE
485 {
486 $$ = alloc_cmd();
487 if (!$$)
488 YYERROR;
489
490 filebench_shm->shm_rmode = FILEBENCH_MODE_QALLDONE;
491
492 $$->cmd = NULL;
493 }
494 | FSC_SET FSE_MODE FSC_QUIT FSA_FIRSTDONE
495 {
496 $$ = alloc_cmd();
497 if (!$$)
498 YYERROR;
499
500 filebench_shm->shm_rmode = FILEBENCH_MODE_Q1STDONE;
501
502 $$->cmd = NULL;
503 }
504 | FSC_SET FSE_MODE FSA_NOUSESTATS
505 {
506 $$ = alloc_cmd();
507 if (!$$)
508 YYERROR;
509
510 filebench_log(LOG_INFO, "Disabling CPU usage statistics");
511 filebench_shm->shm_mmode |= FILEBENCH_MODE_NOUSAGE;
512
513 $$->cmd = NULL;
514 };
515
516 quit_command: FSC_QUIT
517 {
518 if (($$ = alloc_cmd()) == NULL)
519 YYERROR;
520 $$->cmd = parser_filebench_shutdown;
521 };
522
523 flowop_list: flowop_command
524 {
525 $$ = $1;
526 }| flowop_list flowop_command
527 {
528 cmd_t *list = NULL;
529 cmd_t *list_end = NULL;
530
531 /* Find end of list */
532 for (list = $1; list != NULL;
533 list = list->cmd_next)
534 list_end = list;
535
536 list_end->cmd_next = $2;
537
538 filebench_log(LOG_DEBUG_IMPL,
539 "flowop_list adding cmd %zx to list %zx", $2, $1);
540
541 $$ = $1;
542 };
543
544 thread: FSE_THREAD t_attr_ops FSK_OPENLST flowop_list FSK_CLOSELST
545 {
546 /*
547 * Allocate a cmd node per thread, with a
548 * list of flowops attached to the cmd_list
549 */
550 if (($$ = alloc_cmd()) == NULL)
551 YYERROR;
552 $$->cmd_list = $4;
553 $$->cmd_attr_list = $2;
554 };
555
556 thread_list: thread
557 {
558 $$ = $1;
559 }| thread_list thread
560 {
561 cmd_t *list = NULL;
562 cmd_t *list_end = NULL;
563
564 /* Find end of list */
565 for (list = $1; list != NULL;
566 list = list->cmd_next)
567 list_end = list;
568
569 list_end->cmd_next = $2;
570
571 filebench_log(LOG_DEBUG_IMPL,
572 "thread_list adding cmd %zx to list %zx", $2, $1);
573
574 $$ = $1;
575 };
576
577 proc_define_command: FSC_DEFINE FSE_PROC p_attr_ops FSK_OPENLST thread_list FSK_CLOSELST
578 {
579 $$ = alloc_cmd();
580 if (!$$)
581 YYERROR;
582 $$->cmd = &parser_proc_define;
583 $$->cmd_list = $5;
584 $$->cmd_attr_list = $3;
585 }
586
587 files_define_command: FSC_DEFINE FSE_FILE file_attr_ops
588 {
589 $$ = alloc_cmd();
590 if (!$$)
591 YYERROR;
592
593 $$->cmd = &parser_file_define;
594 $$->cmd_attr_list = $3;
595 }| FSC_DEFINE FSE_FILESET fileset_attr_ops
596 {
597 $$ = alloc_cmd();
598 if (!$$)
599 YYERROR;
600
601 $$->cmd = &parser_fileset_define;
602 $$->cmd_attr_list = $3;
603 }
604
605 create_command: FSC_CREATE FSE_FILES
606 {
607 if (($$ = alloc_cmd()) == NULL)
608 YYERROR;
609
610 $$->cmd = &parser_fileset_create;
611 };
612
613 sleep_command: FSC_SLEEP FSV_VAL_POSINT
614 {
615 if (($$ = alloc_cmd()) == NULL)
616 YYERROR;
617 $$->cmd = parser_sleep;
618 $$->cmd_qty = $2;
619 }
620 | FSC_SLEEP FSV_VARIABLE
621 {
622 if (($$ = alloc_cmd()) == NULL)
623 YYERROR;
624 $$->cmd = parser_sleep_variable;
625 $$->cmd_tgt1 = fb_stralloc($2);
626 }
627
628 run_command: FSC_RUN FSV_VAL_POSINT
629 {
630 if (($$ = alloc_cmd()) == NULL)
631 YYERROR;
632 $$->cmd = parser_run;
633 $$->cmd_qty = $2;
634 }
635 | FSC_RUN FSV_VARIABLE
636 {
637 if (($$ = alloc_cmd()) == NULL)
638 YYERROR;
639 $$->cmd = parser_run_variable;
640 $$->cmd_tgt1 = fb_stralloc($2);
641 }
642 | FSC_RUN
643 {
644 if (($$ = alloc_cmd()) == NULL)
645 YYERROR;
646 $$->cmd = parser_run;
647 $$->cmd_qty = 0;
648 };
649
650 psrun_command: FSC_PSRUN
651 {
652 if (($$ = alloc_cmd()) == NULL)
653 YYERROR;
654 $$->cmd = parser_psrun;
655 $$->cmd_qty1 = 0;
656 $$->cmd_qty = 0;
657 }
658 | FSC_PSRUN FSV_VAL_NEGINT
659 {
660 if (($$ = alloc_cmd()) == NULL)
661 YYERROR;
662 $$->cmd = parser_psrun;
663 $$->cmd_qty1 = $2;
664 $$->cmd_qty = 0;
665
666 }
667 | FSC_PSRUN FSV_VAL_POSINT
668 {
669 if (($$ = alloc_cmd()) == NULL)
670 YYERROR;
671 $$->cmd = parser_psrun;
672 $$->cmd_qty1 = $2;
673 $$->cmd_qty = 0;
674
675 }
676 | FSC_PSRUN FSV_VAL_NEGINT FSV_VAL_POSINT
677 {
678 if (($$ = alloc_cmd()) == NULL)
679 YYERROR;
680 $$->cmd = parser_psrun;
681 $$->cmd_qty1 = $2;
682 $$->cmd_qty = $3;
683 }
684 | FSC_PSRUN FSV_VAL_POSINT FSV_VAL_POSINT
685 {
686 if (($$ = alloc_cmd()) == NULL)
687 YYERROR;
688 $$->cmd = parser_psrun;
689 $$->cmd_qty1 = $2;
690 $$->cmd_qty = $3;
691 };
692
693 flowop_command: FSE_FLOWOP name
694 {
695 if (($$ = alloc_cmd()) == NULL)
696 YYERROR;
697 $$->cmd_name = fb_stralloc($2);
698 }
699 | flowop_command fo_attr_ops
700 {
701 $1->cmd_attr_list = $2;
702 };
703
704 name: FSV_STRING;
705
706 file_attr_ops: file_attr_op
707 {
708 $$ = $1;
709 }
710 | file_attr_ops FSK_SEPLST file_attr_op
711 {
712 attr_t *attr = NULL;
713 attr_t *list_end = NULL;
714
715 for (attr = $1; attr; attr = attr->attr_next)
716 list_end = attr;
717
718 list_end->attr_next = $3;
719
720 $$ = $1;
721 };
722
723 fileset_attr_ops: fileset_attr_op
724 {
725 $$ = $1;
726 }
727 | fileset_attr_ops FSK_SEPLST fileset_attr_op
728 {
729 attr_t *attr = NULL;
730 attr_t *list_end = NULL;
731
732 for (attr = $1; attr; attr = attr->attr_next)
733 list_end = attr;
734
735 list_end->attr_next = $3;
736
737 $$ = $1;
738 };
739
740 file_attr_op: attrs_define_file FSK_ASSIGN attr_value
741 {
742 $$ = $3;
743 $$->attr_name = $1;
744 }
745 | attrs_define_file
746 {
747 $$ = alloc_attr();
748 if (!$$)
749 YYERROR;
750
751 $$->attr_name = $1;
752 $$->attr_avd = avd_bool_alloc(TRUE);
753 };
754
755 fileset_attr_op: attrs_define_fileset FSK_ASSIGN attr_value
756 {
757 $$ = $3;
758 $$->attr_name = $1;
759 }
760 | attrs_define_fileset
761 {
762 $$ = alloc_attr();
763 if (!$$)
764 YYERROR;
765
766 $$->attr_name = $1;
767 $$->attr_avd = avd_bool_alloc(TRUE);
768 };
769
770 /* attribute parsing for random variables */
771 randvar_attr_ops: randvar_attr_op
772 {
773 $$ = $1;
774 }
775 | randvar_attr_ops FSK_SEPLST randvar_attr_op
776 {
777 attr_t *attr = NULL;
778 attr_t *list_end = NULL;
779
780 for (attr = $1; attr != NULL;
781 attr = attr->attr_next)
782 list_end = attr; /* Find end of list */
783
784 list_end->attr_next = $3;
785
786 $$ = $1;
787 }
788 | randvar_attr_ops FSK_SEPLST FSA_RANDTABLE FSK_ASSIGN FSK_OPENLST probtabentry_list FSK_CLOSELST
789 {
790 attr_t *attr = NULL;
791 attr_t *list_end = NULL;
792
793 for (attr = $1; attr != NULL;
794 attr = attr->attr_next)
795 list_end = attr; /* Find end of list */
796
797
798 if ((attr = alloc_attr()) == NULL)
799 YYERROR;
800
801 attr->attr_name = FSA_RANDTABLE;
802 attr->attr_obj = (void *)$6;
803 list_end->attr_next = attr;
804 $$ = $1;
805 };
806
807 randvar_attr_op: randvar_attr_name FSK_ASSIGN attr_value
808 {
809 $$ = $3;
810 $$->attr_name = $1;
811 }
812 | randvar_attr_name
813 {
814 if (($$ = alloc_attr()) == NULL)
815 YYERROR;
816 $$->attr_name = $1;
817 $$->attr_avd = avd_bool_alloc(TRUE);
818 }
819 | FSA_TYPE FSK_ASSIGN randvar_attr_typop
820 {
821 $$ = $3;
822 $$->attr_name = FSA_TYPE;
823 }
824 | FSA_RANDSRC FSK_ASSIGN randvar_attr_srcop
825 {
826 $$ = $3;
827 $$->attr_name = FSA_RANDSRC;
828 };
829
830 probtabentry: FSK_OPENLST var_int_val FSK_SEPLST var_int_val FSK_SEPLST var_int_val FSK_CLOSELST
831 {
832 if (($$ = alloc_probtabent()) == NULL)
833 YYERROR;
834 $$->pte_percent = $2;
835 $$->pte_segmin = $4;
836 $$->pte_segmax = $6;
837 };
838
839 /* attribute parsing for prob density function table */
840 probtabentry_list: probtabentry
841 {
842 $$ = $1;
843 }
844 | probtabentry_list FSK_SEPLST probtabentry
845 {
846 probtabent_t *pte = NULL;
847 probtabent_t *ptelist_end = NULL;
848
849 for (pte = $1; pte != NULL;
850 pte = pte->pte_next)
851 ptelist_end = pte; /* Find end of prob table entry list */
852
853 ptelist_end->pte_next = $3;
854
855 $$ = $1;
856 };
857
858 p_attr_ops: p_attr_op
859 {
860 $$ = $1;
861 }
862 | p_attr_ops FSK_SEPLST p_attr_op
863 {
864 attr_t *attr = NULL;
865 attr_t *list_end = NULL;
866
867 for (attr = $1; attr != NULL;
868 attr = attr->attr_next)
869 list_end = attr; /* Find end of list */
870
871 list_end->attr_next = $3;
872
873 $$ = $1;
874 };
875
876 p_attr_op: attrs_define_proc FSK_ASSIGN attr_value
877 {
878 $$ = $3;
879 $$->attr_name = $1;
880 }
881 | attrs_define_proc
882 {
883 $$ = alloc_attr();
884 if (!$$)
885 YYERROR;
886 $$->attr_name = $1;
887 $$->attr_avd = avd_bool_alloc(TRUE);
888 };
889
890 /* attribute parsing thread options */
891 t_attr_ops: t_attr_op
892 {
893 $$ = $1;
894 }
895 | t_attr_ops FSK_SEPLST t_attr_op
896 {
897 attr_t *attr = NULL;
898 attr_t *list_end = NULL;
899
900 for (attr = $1; attr != NULL;
901 attr = attr->attr_next)
902 list_end = attr; /* Find end of list */
903
904 list_end->attr_next = $3;
905
906 $$ = $1;
907 };
908
909 t_attr_op: attrs_define_thread FSK_ASSIGN attr_value
910 {
911 $$ = $3;
912 $$->attr_name = $1;
913 }
914 | attrs_define_thread
915 {
916 if (($$ = alloc_attr()) == NULL)
917 YYERROR;
918 $$->attr_name = $1;
919 $$->attr_avd = avd_bool_alloc(TRUE);
920 };
921
922 /* attribute parsing for flowops */
923 fo_attr_ops: fo_attr_op
924 {
925 $$ = $1;
926 }
927 | fo_attr_ops FSK_SEPLST fo_attr_op
928 {
929 attr_t *attr = NULL;
930 attr_t *list_end = NULL;
931
932 for (attr = $1; attr != NULL;
933 attr = attr->attr_next)
934 list_end = attr; /* Find end of list */
935
936 list_end->attr_next = $3;
937
938 $$ = $1;
939 }
940 | fo_attr_ops FSK_SEPLST comp_lvar_def
941 {
942 attr_t *attr = NULL;
943 attr_t *list_end = NULL;
944
945 for (attr = $1; attr != NULL;
946 attr = attr->attr_next)
947 list_end = attr; /* Find end of list */
948
949 list_end->attr_next = $3;
950
951 $$ = $1;
952 };
953
954 fo_attr_op: attrs_flowop FSK_ASSIGN attr_value
955 {
956 $$ = $3;
957 $$->attr_name = $1;
958 }
959 | attrs_flowop
960 {
961 if (($$ = alloc_attr()) == NULL)
962 YYERROR;
963 $$->attr_name = $1;
964 $$->attr_avd = avd_bool_alloc(TRUE);
965 };
966
967 /* attribute parsing for Event Generator */
968 ev_attr_ops: ev_attr_op
969 {
970 $$ = $1;
971 }
972 | ev_attr_ops FSK_SEPLST ev_attr_op
973 {
974 attr_t *attr = NULL;
975 attr_t *list_end = NULL;
976
977 for (attr = $1; attr != NULL;
978 attr = attr->attr_next)
979 list_end = attr; /* Find end of list */
980
981 list_end->attr_next = $3;
982
983 $$ = $1;
984 };
985
986 ev_attr_op: attrs_eventgen FSK_ASSIGN attr_value
987 {
988 $$ = $3;
989 $$->attr_name = $1;
990 }
991 | attrs_eventgen
992 {
993 if (($$ = alloc_attr()) == NULL)
994 YYERROR;
995 $$->attr_name = $1;
996 $$->attr_avd = avd_bool_alloc(TRUE);
997 };
998
999 /* attribute parsing for enable multiple client command */
1000 enable_multi_ops: enable_multi_op
1001 {
1002 $$ = $1;
1003 }
1004 | enable_multi_ops FSK_SEPLST enable_multi_op
1005 {
1006 attr_t *attr = NULL;
1007 attr_t *list_end = NULL;
1008
1009 for (attr = $1; attr != NULL;
1010 attr = attr->attr_next)
1011 list_end = attr; /* Find end of list */
1012
1013 list_end->attr_next = $3;
1014
1015 $$ = $1;
1016 };
1017
1018 enable_multi_op: em_attr_name FSK_ASSIGN attr_value
1019 {
1020 $$ = $3;
1021 $$->attr_name = $1;
1022 };
1023
1024 multisync_op: FSA_VALUE FSK_ASSIGN attr_value
1025 {
1026 $$ = $3;
1027 $$->attr_name = FSA_VALUE;
1028 };
1029
1030 /*
1031 * Attribute names
1032 */
1033 attrs_define_proc:
1034 FSA_NAME { $$ = FSA_NAME;}
1035 | FSA_INSTANCES { $$ = FSA_INSTANCES;}
1036 | FSA_NICE { $$ = FSA_NICE;}
1037
1038 attrs_define_file:
1039 FSA_NAME { $$ = FSA_NAME;}
1040 | FSA_PATH { $$ = FSA_PATH;}
1041 | FSA_SIZE { $$ = FSA_SIZE;}
1042 | FSA_PREALLOC { $$ = FSA_PREALLOC;}
1043 | FSA_PARALLOC { $$ = FSA_PARALLOC;}
1044 | FSA_REUSE { $$ = FSA_REUSE;}
1045 | FSA_TRUSTTREE { $$ = FSA_TRUSTTREE;}
1046 | FSA_READONLY { $$ = FSA_READONLY;}
1047 | FSA_WRITEONLY { $$ = FSA_WRITEONLY;}
1048
1049 attrs_define_fileset:
1050 FSA_NAME { $$ = FSA_NAME;}
1051 | FSA_PATH { $$ = FSA_PATH;}
1052 | FSA_ENTRIES { $$ = FSA_ENTRIES;}
1053 | FSA_SIZE { $$ = FSA_SIZE;}
1054 | FSA_PREALLOC { $$ = FSA_PREALLOC;}
1055 | FSA_PARALLOC { $$ = FSA_PARALLOC;}
1056 | FSA_REUSE { $$ = FSA_REUSE;}
1057 | FSA_TRUSTTREE { $$ = FSA_TRUSTTREE;}
1058 | FSA_READONLY { $$ = FSA_READONLY;}
1059 | FSA_WRITEONLY { $$ = FSA_WRITEONLY;}
1060 | FSA_DIRWIDTH { $$ = FSA_DIRWIDTH;}
1061 | FSA_DIRDEPTHRV { $$ = FSA_DIRDEPTHRV;}
1062 | FSA_DIRGAMMA { $$ = FSA_DIRGAMMA;}
1063 | FSA_LEAFDIRS { $$ = FSA_LEAFDIRS;};
1064
1065 randvar_attr_name:
1066 FSA_NAME { $$ = FSA_NAME;}
1067 | FSA_RANDSEED { $$ = FSA_RANDSEED;}
1068 | FSA_RANDGAMMA { $$ = FSA_RANDGAMMA;}
1069 | FSA_RANDMEAN { $$ = FSA_RANDMEAN;}
1070 | FSA_MIN { $$ = FSA_MIN;}
1071 | FSA_ROUND { $$ = FSA_ROUND;};
1072
1073 randvar_attr_typop: randtype_name
1074 {
1075 if (($$ = alloc_attr()) == NULL)
1076 YYERROR;
1077 $$->attr_avd = avd_int_alloc($1);
1078 };
1079
1080 randtype_name:
1081 FSV_RANDUNI { $$ = FSV_RANDUNI;}
1082 | FSV_RANDTAB { $$ = FSV_RANDTAB;}
1083 | FSA_RANDGAMMA { $$ = FSA_RANDGAMMA;};
1084
1085 randvar_attr_srcop: randsrc_name
1086 {
1087 if (($$ = alloc_attr()) == NULL)
1088 YYERROR;
1089 $$->attr_avd = avd_int_alloc($1);
1090 };
1091
1092 randsrc_name:
1093 FSV_URAND { $$ = FSV_URAND;}
1094 | FSV_RAND48 { $$ = FSV_RAND48;};
1095
1096 cvar_attr_name:
1097 FSA_TYPE { $$ = FSA_TYPE;}
1098 | FSA_PARAMETERS { $$ = FSA_PARAMETERS;}
1099 | FSA_MIN { $$ = FSA_MIN;}
1100 | FSA_MAX { $$ = FSA_MAX;}
1101 | FSA_ROUND { $$ = FSA_ROUND;};
1102
1103 attrs_define_thread:
1104 FSA_NAME { $$ = FSA_NAME;}
1105 | FSA_MEMSIZE { $$ = FSA_MEMSIZE;}
1106 | FSA_USEISM { $$ = FSA_USEISM;}
1107 | FSA_INSTANCES { $$ = FSA_INSTANCES;}
1108 | FSA_IOPRIO { $$ = FSA_IOPRIO;};
1109
1110 attrs_flowop:
1111 FSA_WSS { $$ = FSA_WSS;}
1112 | FSA_FILENAME { $$ = FSA_FILENAME;}
1113 | FSA_NAME { $$ = FSA_NAME;}
1114 | FSA_RANDOM { $$ = FSA_RANDOM;}
1115 | FSA_FD { $$ = FSA_FD;}
1116 | FSA_SRCFD { $$ = FSA_SRCFD;}
1117 | FSA_ROTATEFD { $$ = FSA_ROTATEFD;}
1118 | FSA_DSYNC { $$ = FSA_DSYNC;}
1119 | FSA_DIRECTIO { $$ = FSA_DIRECTIO;}
1120 | FSA_INDEXED { $$ = FSA_INDEXED;}
1121 | FSA_TARGET { $$ = FSA_TARGET;}
1122 | FSA_ITERS { $$ = FSA_ITERS;}
1123 | FSA_VALUE { $$ = FSA_VALUE;}
1124 | FSA_BLOCKING { $$ = FSA_BLOCKING;}
1125 | FSA_HIGHWATER { $$ = FSA_HIGHWATER;}
1126 | FSA_IOSIZE { $$ = FSA_IOSIZE;}
1127 | FSA_NOREADAHEAD { $$ = FSA_NOREADAHEAD;};
1128
1129 attrs_eventgen:
1130 FSA_RATE { $$ = FSA_RATE;};
1131
1132 em_attr_name:
1133 FSA_MASTER { $$ = FSA_MASTER;}
1134 | FSA_CLIENT { $$ = FSA_CLIENT;};
1135
1136 comp_attr_ops: comp_attr_op
1137 {
1138 $$ = $1;
1139 }
1140 | comp_attr_ops FSK_SEPLST comp_attr_op
1141 {
1142 attr_t *attr = NULL;
1143 attr_t *list_end = NULL;
1144
1145 for (attr = $1; attr != NULL;
1146 attr = attr->attr_next)
1147 list_end = attr; /* Find end of list */
1148
1149 list_end->attr_next = $3;
1150
1151 $$ = $1;
1152 }
1153 | comp_attr_ops FSK_SEPLST comp_lvar_def
1154 {
1155 attr_t *attr = NULL;
1156 attr_t *list_end = NULL;
1157
1158 for (attr = $1; attr != NULL;
1159 attr = attr->attr_next)
1160 list_end = attr; /* Find end of list */
1161
1162 list_end->attr_next = $3;
1163
1164 $$ = $1;
1165 };
1166
1167 comp_attr_op: attrs_define_comp FSK_ASSIGN attr_value
1168 {
1169 $$ = $3;
1170 $$->attr_name = $1;
1171 };
1172
1173 comp_lvar_def: FSV_VARIABLE FSK_ASSIGN FSV_VAL_BOOLEAN
1174 {
1175 if (($$ = alloc_lvar_attr(var_lvar_assign_boolean($1, $3))) == NULL)
1176 YYERROR;
1177 }
1178 | FSV_VARIABLE FSK_ASSIGN FSV_VAL_POSINT
1179 {
1180 if (($$ = alloc_lvar_attr(var_lvar_assign_integer($1, $3))) == NULL)
1181 YYERROR;
1182 }
1183 | FSV_VARIABLE FSK_ASSIGN FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
1184 {
1185 if (($$ = alloc_lvar_attr(var_lvar_assign_string($1, $4))) == NULL)
1186 YYERROR;
1187 }
1188 | FSV_VARIABLE FSK_ASSIGN FSV_STRING
1189 {
1190 if (($$ = alloc_lvar_attr(var_lvar_assign_string($1, $3))) == NULL)
1191 YYERROR;
1192 }
1193 | FSV_VARIABLE FSK_ASSIGN FSV_VARIABLE
1194 {
1195 if (($$ = alloc_lvar_attr(var_lvar_assign_var($1, $3))) == NULL)
1196 YYERROR;
1197 }
1198 | FSV_VARIABLE
1199 {
1200 if (($$ = alloc_lvar_attr(var_lvar_alloc_local($1))) == NULL)
1201 YYERROR;
1202 };
1203
1204 flowop_define_command: FSC_DEFINE FSE_FLOWOP comp_attr_ops FSK_OPENLST flowop_list FSK_CLOSELST
1205 {
1206 if (($$ = alloc_cmd()) == NULL)
1207 YYERROR;
1208 $$->cmd = &parser_composite_flowop_define;
1209 $$->cmd_list = $5;
1210 $$->cmd_attr_list = $3;
1211 }
1212 | flowop_define_command comp_attr_ops
1213 {
1214 $1->cmd_attr_list = $2;
1215 };
1216
1217 /* attribute parsing for custom variables */
1218 cvar_attr_ops: cvar_attr_op
1219 {
1220 $$ = $1;
1221 }
1222 | cvar_attr_ops FSK_SEPLST cvar_attr_op
1223 {
1224 attr_t *attr = NULL;
1225 attr_t *list_end = NULL;
1226
1227 for (attr = $1; attr != NULL;
1228 attr = attr->attr_next)
1229 list_end = attr; /* Find end of list */
1230
1231 list_end->attr_next = $3;
1232
1233 $$ = $1;
1234 }
1235
1236 cvar_attr_op: cvar_attr_name FSK_ASSIGN attr_value
1237 {
1238 $$ = $3;
1239 $$->attr_name = $1;
1240 };
1241
1242 attrs_define_comp:
1243 FSA_NAME { $$ = FSA_NAME;}
1244 | FSA_ITERS { $$ = FSA_ITERS;};
1245
1246 attr_value: FSV_STRING
1247 {
1248 $$ = alloc_attr();
1249 if (!$$)
1250 YYERROR;
1251 $$->attr_avd = avd_str_alloc($1);
1252 } | FSK_QUOTE FSV_WHITESTRING FSK_QUOTE {
1253 $$ = alloc_attr();
1254 if (!$$)
1255 YYERROR;
1256 $$->attr_avd = avd_str_alloc($2);
1257 } | FSV_VAL_POSINT {
1258 $$ = alloc_attr();
1259 if (!$$)
1260 YYERROR;
1261 $$->attr_avd = avd_int_alloc($1);
1262 } | FSV_VAL_BOOLEAN {
1263 $$ = alloc_attr();
1264 if (!$$)
1265 YYERROR;
1266 $$->attr_avd = avd_bool_alloc($1);
1267 } | FSV_VARIABLE {
1268 $$ = alloc_attr();
1269 if (!$$)
1270 YYERROR;
1271 $$->attr_avd = avd_var_alloc($1);
1272 };
1273
1274 var_int_val: FSV_VAL_POSINT
1275 {
1276 $$ = avd_int_alloc($1);
1277 } | FSV_VARIABLE
1278 {
1279 $$ = avd_var_alloc($1);
1280 };
1281
1282 %%
1283
1284 /*
1285 * The following C routines implement the various commands defined in the above
1286 * yacc parser code. The yacc portion checks the syntax of the commands found
1287 * in a workload file and parses the commands' parameters into lists. The lists
1288 * are then passed in a cmd_t struct for each command to its related routine in
1289 * the following section for actual execution. This section also includes a
1290 * few utility routines and the main entry point for the program.
1291 */
1292
1293 #define USAGE \
1294 "Usage: " \
1295 "filebench {-f <wmlscript> | -h | -c [cvartype]}\n\n" \
1296 " Filebench version " FILEBENCH_VERSION "\n\n" \
1297 " Filebench is a file system and storage benchmark that interprets a script\n" \
1298 " written in its Workload Model Language (WML), and procees to generate the\n" \
1299 " specified workload. Refer to the README for more details.\n\n" \
1300 " Visit github.com/filebench/filebench for WML definition and tutorials.\n\n" \
1301 "Options:\n" \
1302 " -f <wmlscript> generate workload from the specified file\n" \
1303 " -h display this help message\n" \
1304 " -c display supported cvar types\n" \
1305 " -c [cvartype] display options of the specific cvar type\n\n"
1306
1307 static void
1308 usage_exit(int ret, const char *msg)
1309 {
1310 if (ret) {
1311 (void)fprintf(stderr, "Usage error: %s\n\n", msg);
1312 (void)fprintf(stderr, USAGE);
1313 } else
1314 printf(USAGE);
1315 exit(ret);
1316 }
1317
1318 struct fbparams {
1319 char *execname;
1320 char *fscriptname;
1321 char *procname;
1322 char *shmaddr;
1323 char *shmpath;
1324 int instance;
1325 char *cvartype;
1326 };
1327
1328 static void
init_fbparams(struct fbparams * fbparams)1329 init_fbparams(struct fbparams *fbparams)
1330 {
1331 memset(fbparams, 0, sizeof(*fbparams));
1332 fbparams->instance = -1;
1333 }
1334
1335 #define FB_MODE_NONE 0
1336 #define FB_MODE_HELP 1
1337 #define FB_MODE_MASTER 2
1338 #define FB_MODE_WORKER 3
1339 #define FB_MODE_CVARS 4
1340
1341 static int
parse_options(int argc,char * argv[],struct fbparams * fbparams)1342 parse_options(int argc, char *argv[], struct fbparams *fbparams)
1343 {
1344 const char cmd_options[] = "m:s:a:i:hf:c:";
1345 int mode = FB_MODE_NONE;
1346 int opt;
1347
1348 init_fbparams(fbparams);
1349 fbparams->execname = argv[0];
1350
1351 /*
1352 * We don't want getopt() to print error messages because
1353 * sometimes what it percieves as an error is actually not
1354 * an error. For example, "-c" option might have or might
1355 * not have an argument. If opterr is non-zero, getopt()
1356 * prints an error message when "-c"'s argument is missing.
1357 */
1358 opterr = 0;
1359
1360 /* Either
1361 (-f <wmlscript>) or
1362 (-a and -s and -m and -i) or
1363 (-c [cvartype]) or
1364 (-h)
1365 must be specified */
1366 while ((opt = getopt(argc, argv, cmd_options)) > 0) {
1367 switch (opt) {
1368 /* public parameters */
1369 case 'h':
1370 if (mode != FB_MODE_NONE)
1371 usage_exit(1, "Too many options specified");
1372 mode = FB_MODE_HELP;
1373 break;
1374 case 'c':
1375 if (mode != FB_MODE_NONE)
1376 usage_exit(1, "Too many options specified");
1377 mode = FB_MODE_CVARS;
1378 fbparams->cvartype = optarg;
1379 break;
1380 case 'f':
1381 if (mode != FB_MODE_NONE)
1382 usage_exit(1, "Too many options specified");
1383 mode = FB_MODE_MASTER;
1384 fbparams->fscriptname = optarg;
1385 break;
1386 /* private parameters: when filebench calls itself */
1387 case 'a':
1388 if (mode != FB_MODE_NONE &&
1389 (mode != FB_MODE_WORKER || fbparams->procname))
1390 usage_exit(1, "Too many options");
1391 mode = FB_MODE_WORKER;
1392 fbparams->procname = optarg;
1393 break;
1394 case 's':
1395 if (mode != FB_MODE_NONE &&
1396 (mode != FB_MODE_WORKER || fbparams->shmaddr))
1397 usage_exit(1, "Too many options");
1398 mode = FB_MODE_WORKER;
1399 sscanf(optarg, "%p", &fbparams->shmaddr);
1400 break;
1401 case 'm':
1402 if (mode != FB_MODE_NONE &&
1403 (mode != FB_MODE_WORKER || fbparams->shmpath))
1404 usage_exit(1, "Too many options");
1405 mode = FB_MODE_WORKER;
1406 fbparams->shmpath = optarg;
1407 break;
1408 case 'i':
1409 if (mode != FB_MODE_NONE &&
1410 (mode != FB_MODE_WORKER || fbparams->instance != -1))
1411 usage_exit(1, "Too many options");
1412 mode = FB_MODE_WORKER;
1413 sscanf(optarg, "%d", &fbparams->instance);
1414 break;
1415 case '?':
1416 if (optopt == 'c') {
1417 if (mode != FB_MODE_NONE)
1418 usage_exit(1, "Too many options");
1419 mode = FB_MODE_CVARS;
1420 break;
1421 }
1422 default:
1423 usage_exit(1, "Unrecognized option");
1424 break;
1425 }
1426 }
1427
1428 if (mode == FB_MODE_NONE)
1429 usage_exit(1, "No runtime options specified");
1430
1431 if (mode == FB_MODE_WORKER) {
1432 if (!fbparams->procname ||
1433 !fbparams->shmaddr ||
1434 !fbparams->shmpath ||
1435 fbparams->instance == -1)
1436 usage_exit(1, "Invalid worker settings");
1437 }
1438
1439 return mode;
1440 }
1441
1442 static void
worker_mode(struct fbparams * fbparams)1443 worker_mode(struct fbparams *fbparams)
1444 {
1445 int ret;
1446
1447 ret = ipc_attach(fbparams->shmaddr, fbparams->shmpath);
1448 if (ret < 0) {
1449 filebench_log(LOG_FATAL, "Cannot attach shm for %s",
1450 fbparams->procname);
1451 exit(1);
1452 }
1453
1454 /* get correct function pointer for each working process */
1455 flowop_init(0);
1456
1457 /* load custom variable libraries and revalidate handles */
1458 ret = init_cvar_libraries();
1459 if (ret)
1460 exit(1);
1461
1462 ret = revalidate_cvar_handles();
1463 if (ret)
1464 exit(1);
1465
1466 /* execute corresponding procflow */
1467 ret = procflow_exec(fbparams->procname, fbparams->instance);
1468 if (ret < 0) {
1469 filebench_log(LOG_FATAL, "Cannot startup process %s",
1470 fbparams->procname);
1471 exit(1);
1472 }
1473
1474 exit(0);
1475 }
1476
parser_list_cvar_types(void)1477 void parser_list_cvar_types(void)
1478 {
1479 cvar_library_info_t *t;
1480
1481 if (!filebench_shm->shm_cvar_lib_info_list) {
1482 printf("No custom variables supported.\n");
1483 return;
1484 }
1485
1486 printf("Custom variable types supported:\n");
1487 for (t = filebench_shm->shm_cvar_lib_info_list; t; t = t->next)
1488 printf(" %s\n", t->type);
1489
1490 return;
1491 }
1492
parser_list_cvar_type_parameters(char * type)1493 void parser_list_cvar_type_parameters(char *type)
1494 {
1495 const char *version = NULL;
1496 const char *usage = NULL;
1497
1498 cvar_library_info_t *t;
1499
1500 for (t = filebench_shm->shm_cvar_lib_info_list; t != NULL; t = t->next) {
1501 if (!strcmp(type, t->type))
1502 break;
1503 }
1504
1505 if (!t) {
1506 printf("Unknown custom variable type %s.\n", type);
1507 return;
1508 }
1509
1510 printf("Custom variable type: %s\n", t->type);
1511 printf("Supporting library: %s\n", t->filename);
1512
1513 if (cvar_libraries[t->index]->cvar_op.cvar_version)
1514 version = cvar_libraries[t->index]->cvar_op.cvar_version();
1515
1516 if (cvar_libraries[t->index]->cvar_op.cvar_usage)
1517 usage = cvar_libraries[t->index]->cvar_op.cvar_usage();
1518
1519
1520 if (version)
1521 printf("Version: %s\n", version);
1522 else
1523 printf("Oops. No version information provided.\n");
1524
1525 if (usage)
1526 printf("Usage:\n%s\n", usage);
1527 else
1528 printf("Oops. No usage information provided.\n");
1529
1530 return;
1531 }
1532
1533 static void
cvars_mode(struct fbparams * fbparams)1534 cvars_mode(struct fbparams *fbparams)
1535 {
1536 int ret;
1537
1538 ipc_init();
1539
1540 ret = init_cvar_library_info(FBLIBDIR);
1541 if (ret)
1542 filebench_shutdown(1);
1543
1544 ret = init_cvar_libraries();
1545 if (ret)
1546 filebench_shutdown(1);
1547
1548 if (fbparams->cvartype)
1549 parser_list_cvar_type_parameters(fbparams->cvartype);
1550 else
1551 parser_list_cvar_types();
1552
1553 ipc_fini();
1554
1555 exit(0);
1556 }
1557
1558 /*
1559 * Shutdown filebench.
1560 */
1561 static void
parser_abort(int arg)1562 parser_abort(int arg)
1563 {
1564 (void) sigignore(SIGINT);
1565 filebench_log(LOG_INFO, "Aborting...");
1566 filebench_shutdown(1);
1567 }
1568
1569 static void
master_mode(struct fbparams * fbparams)1570 master_mode(struct fbparams *fbparams) {
1571 int ret;
1572
1573 printf("Filebench Version %s\n", FILEBENCH_VERSION);
1574
1575 yyin = fopen(fbparams->fscriptname, "r");
1576 if (!yyin) {
1577 filebench_log(LOG_FATAL,
1578 "Cannot open file %s!", fbparams->fscriptname);
1579 exit(1);
1580 }
1581
1582 execname = fbparams->execname;
1583 fb_set_shmmax();
1584
1585 ipc_init();
1586
1587 /* Below we initialize things that depend on IPC */
1588 (void)strcpy(filebench_shm->shm_fscriptname,
1589 fbparams->fscriptname);
1590
1591 flowop_init(1);
1592 eventgen_init();
1593
1594 /* Initialize custom variables. */
1595 ret = init_cvar_library_info(FBLIBDIR);
1596 if (ret)
1597 filebench_shutdown(1);
1598
1599 ret = init_cvar_libraries();
1600 if (ret)
1601 filebench_shutdown(1);
1602
1603 signal(SIGINT, parser_abort);
1604
1605 /* yyparse() after it parsed complete grammar */
1606 yyparse();
1607
1608 /* We only get here if there was no
1609 run (or similar) command in the
1610 end of the WML script. */
1611 printf("Warning: no run command in the WML script!\n");
1612 parser_filebench_shutdown((cmd_t *)0);
1613 }
1614
1615 static void
init_common()1616 init_common()
1617 {
1618 disable_aslr();
1619 my_pid = getpid();
1620 fb_set_rlimit();
1621 }
1622
1623 /*
1624 * Entry point for Filebench. Processes command line arguments. The -f option
1625 * will read in a workload file (the full name and extension must must be
1626 * given). The -a, -s, -m and -i options are used by the worker process to
1627 * receive the name, the base address of shared memory, its path, and the
1628 * process' instance number, respectively. This information is supplied by the
1629 * master process when it execs worker processes. If the worker process
1630 * arguments are passed then main will call the procflow_exec() routine which
1631 * creates worker threadflows and flowops and executes the procflow's portion of
1632 * the workload model until completion. If worker process arguments are not
1633 * passed to the process, then it becomes the master process for a filebench
1634 * run. It initializes the various filebench components and either executes the
1635 * supplied workload file, or enters interactive mode.
1636 */
1637 int
main(int argc,char * argv[])1638 main(int argc, char *argv[])
1639 {
1640 struct fbparams fbparams;
1641 int mode;
1642
1643 /* parse_options() exits if detects wrong usage */
1644 mode = parse_options(argc, argv, &fbparams);
1645
1646 if (mode == FB_MODE_HELP)
1647 usage_exit(0, NULL);
1648
1649 if (mode == FB_MODE_CVARS)
1650 cvars_mode(&fbparams);
1651
1652 init_common();
1653
1654 if (mode == FB_MODE_MASTER)
1655 master_mode(&fbparams);
1656
1657 if (mode == FB_MODE_WORKER)
1658 worker_mode(&fbparams);
1659
1660 /* We should never reach this point */
1661 return 0;
1662 }
1663
1664 /*
1665 * Converts a list of var_strings or ordinary strings to a single ordinary
1666 * string. It returns a pointer to the string (in malloc'd memory) if found,
1667 * or NULL otherwise.
1668 */
1669 char *
parser_list2string(list_t * list)1670 parser_list2string(list_t *list)
1671 {
1672 list_t *l;
1673 char *string;
1674 char *tmp;
1675
1676 string = malloc(MAXPATHLEN);
1677 if (!string) {
1678 filebench_log(LOG_ERROR, "Failed to allocate memory");
1679 return NULL;
1680 }
1681
1682 *string = 0;
1683
1684 /* Format args */
1685 for (l = list; l != NULL; l = l->list_next) {
1686
1687 char *lstr = avd_get_str(l->list_string);
1688
1689 filebench_log(LOG_DEBUG_SCRIPT, "converting string '%s'", lstr);
1690
1691 /* see if it is a random variable */
1692 if (l->list_integer) {
1693 fbint_t param_name;
1694
1695 tmp = NULL;
1696 param_name = avd_get_int(l->list_integer);
1697
1698 switch (param_name) {
1699 case FSS_TYPE:
1700 tmp = var_randvar_to_string(lstr,
1701 RAND_PARAM_TYPE);
1702 break;
1703
1704 case FSS_SRC:
1705 tmp = var_randvar_to_string(lstr,
1706 RAND_PARAM_SRC);
1707 break;
1708
1709 case FSS_SEED:
1710 tmp = var_randvar_to_string(lstr,
1711 RAND_PARAM_SEED);
1712 break;
1713
1714 case FSS_MIN:
1715 tmp = var_randvar_to_string(lstr,
1716 RAND_PARAM_MIN);
1717 break;
1718
1719 case FSS_MEAN:
1720 tmp = var_randvar_to_string(lstr,
1721 RAND_PARAM_MEAN);
1722 break;
1723
1724 case FSS_GAMMA:
1725 tmp = var_randvar_to_string(lstr,
1726 RAND_PARAM_GAMMA);
1727 break;
1728
1729 case FSS_ROUND:
1730 tmp = var_randvar_to_string(lstr,
1731 RAND_PARAM_ROUND);
1732 break;
1733 }
1734
1735 if (tmp) {
1736 (void) strcat(string, tmp);
1737 free(tmp);
1738 } else {
1739 (void) strcat(string, lstr);
1740 }
1741 } else {
1742 /* perhaps a normal variable? */
1743 if ((tmp = var_to_string(lstr)) != NULL) {
1744 (void) strcat(string, tmp);
1745 free(tmp);
1746 } else {
1747 (void) strcat(string, lstr);
1748 }
1749 }
1750 }
1751
1752 return string;
1753 }
1754
1755 /*
1756 * If the list just contains a single string starting with '$', then find
1757 * or create the named var and return the var's var_string component.
1758 * Otherwise, convert the list to a string, and allocate a var_string
1759 * containing a copy of that string. On failure either returns NULL
1760 * or shuts down the run.
1761 */
1762 avd_t
parser_list2varstring(list_t * list)1763 parser_list2varstring(list_t *list)
1764 {
1765 char *lstr = avd_get_str(list->list_string);
1766
1767 /* Special case - variable name */
1768 if ((list->list_next == NULL) && (*lstr == '$'))
1769 return avd_var_alloc(lstr);
1770
1771 return (avd_str_alloc(parser_list2string(list)));
1772 }
1773
1774 /*
1775 * Looks for the var named in list_string of the first element of the
1776 * supplied list. If found, returns the var_val portion of the var in
1777 * an attribute value descriptor. If the var is not found, cannot be
1778 * allocated, the supplied list is NULL, or the list_string filed is
1779 * empty, returns NULL.
1780 */
1781 avd_t
parser_list2avd(list_t * list)1782 parser_list2avd(list_t *list)
1783 {
1784 avd_t avd;
1785 char *lstr;
1786
1787 if (list && ((lstr = avd_get_str(list->list_string)) != NULL)) {
1788 avd = avd_var_alloc(lstr);
1789 return (avd);
1790 }
1791
1792 return (NULL);
1793 }
1794
1795 /*
1796 * Sets the event generator rate from the attribute supplied with the
1797 * command. If the attribute doesn't exist the routine does nothing.
1798 */
1799 static void
parser_eventgen(cmd_t * cmd)1800 parser_eventgen(cmd_t *cmd)
1801 {
1802 attr_t *attr;
1803
1804 /* Get the rate from attribute */
1805 if ((attr = get_attr(cmd, FSA_RATE))) {
1806 if (attr->attr_avd) {
1807 eventgen_setrate(attr->attr_avd);
1808 }
1809 }
1810 }
1811
1812 /*
1813 * Lists the fileset name, path name and average size for all defined
1814 * filesets.
1815 */
1816 static void
parser_fileset_list(cmd_t * cmd)1817 parser_fileset_list(cmd_t *cmd)
1818 {
1819 (void) fileset_iter(fileset_print);
1820 }
1821
1822 /*
1823 * Lists the flowop name and instance number for all flowops.
1824 */
1825 static void
parser_flowop_list(cmd_t * cmd)1826 parser_flowop_list(cmd_t *cmd)
1827 {
1828 flowop_printall();
1829 }
1830
1831 /*
1832 * Calls procflow_define() to allocate "instances" number of procflow(s)
1833 * (processes) with the supplied name. The default number of instances is
1834 * one. An optional priority level attribute can be supplied and is stored in
1835 * pf_nice. Finally the routine loops through the list of inner commands, if
1836 * any, which are defines for threadflows, and passes them one at a time to
1837 * parser_thread_define() to allocate threadflow entities for the process(es).
1838 */
1839 static void
parser_proc_define(cmd_t * cmd)1840 parser_proc_define(cmd_t *cmd)
1841 {
1842 procflow_t *procflow;
1843 char *name = NULL;
1844 attr_t *attr;
1845 avd_t var_instances;
1846 fbint_t instances;
1847 cmd_t *inner_cmd;
1848
1849 attr = get_attr(cmd, FSA_NAME);
1850 if (attr)
1851 name = avd_get_str(attr->attr_avd);
1852 else {
1853 filebench_log(LOG_ERROR, "process specifies no name");
1854 filebench_shutdown(1);
1855 }
1856
1857 attr = get_attr(cmd, FSA_INSTANCES);
1858 if (attr) {
1859 var_instances = attr->attr_avd;
1860 instances = avd_get_int(var_instances);
1861 filebench_log(LOG_DEBUG_IMPL,
1862 "Setting instances = %llu", (u_longlong_t)instances);
1863 } else {
1864 filebench_log(LOG_DEBUG_IMPL,
1865 "Defaulting to instances = 1");
1866 var_instances = avd_int_alloc(1);
1867 instances = 1;
1868 }
1869
1870 procflow = procflow_define(name, var_instances);
1871 if (!procflow) {
1872 filebench_log(LOG_ERROR,
1873 "Failed to instantiate %d %s process(es)\n",
1874 instances, name);
1875 filebench_shutdown(1);
1876 }
1877
1878 attr = get_attr(cmd, FSA_NICE);
1879 if (attr) {
1880 filebench_log(LOG_DEBUG_IMPL, "Setting pri = %llu",
1881 (u_longlong_t)avd_get_int(attr->attr_avd));
1882 procflow->pf_nice = attr->attr_avd;
1883 } else
1884 procflow->pf_nice = avd_int_alloc(0);
1885
1886 /* Create the list of threads for this process */
1887 for (inner_cmd = cmd->cmd_list; inner_cmd;
1888 inner_cmd = inner_cmd->cmd_next)
1889 parser_thread_define(inner_cmd, procflow);
1890 }
1891
1892 /*
1893 * Calls threadflow_define() to allocate "instances" number of threadflow(s)
1894 * (threads) with the supplied name. The default number of instances is
1895 * one. Two other optional attributes may be supplied, one to set the memory
1896 * size, stored in tf_memsize, and to select the use of Interprocess Shared
1897 * Memory, which sets the THREADFLOW_USEISM flag in tf_attrs. Finally
1898 * the routine loops through the list of inner commands, if any, which are
1899 * defines for flowops, and passes them one at a time to
1900 * parser_flowop_define() to allocate flowop entities for the threadflows.
1901 */
1902 static void
parser_thread_define(cmd_t * cmd,procflow_t * procflow)1903 parser_thread_define(cmd_t *cmd, procflow_t *procflow)
1904 {
1905 threadflow_t *threadflow, template;
1906 attr_t *attr;
1907 avd_t instances;
1908 cmd_t *inner_cmd;
1909 char *name = NULL;
1910
1911 memset(&template, 0, sizeof (threadflow_t));
1912
1913 attr = get_attr(cmd, FSA_NAME);
1914 if (attr)
1915 name = avd_get_str(attr->attr_avd);
1916 else {
1917 filebench_log(LOG_ERROR,
1918 "thread in process %s specifies no name",
1919 procflow->pf_name);
1920 filebench_shutdown(1);
1921 }
1922
1923 attr = get_attr(cmd, FSA_INSTANCES);
1924 if (attr)
1925 instances = attr->attr_avd;
1926 else
1927 instances = avd_int_alloc(1);
1928
1929 attr = get_attr(cmd, FSA_MEMSIZE);
1930 if (attr)
1931 template.tf_memsize = attr->attr_avd;
1932 else /* XXX: really, memsize zero is default?.. */
1933 template.tf_memsize = avd_int_alloc(0);
1934
1935 attr = get_attr(cmd, FSA_IOPRIO);
1936 if (attr)
1937 template.tf_ioprio = attr->attr_avd;
1938 else /* XXX: really, ioprio is 8 by default?.. */
1939 template.tf_ioprio = avd_int_alloc(8);
1940
1941
1942 threadflow = threadflow_define(procflow, name, &template, instances);
1943 if (!threadflow) {
1944 filebench_log(LOG_ERROR,
1945 "failed to instantiate thread\n");
1946 filebench_shutdown(1);
1947 }
1948
1949 attr = get_attr(cmd, FSA_USEISM);
1950 if (attr)
1951 threadflow->tf_attrs |= THREADFLOW_USEISM;
1952
1953 /* create the list of flowops */
1954 for (inner_cmd = cmd->cmd_list; inner_cmd;
1955 inner_cmd = inner_cmd->cmd_next)
1956 parser_flowop_define(inner_cmd, threadflow,
1957 &threadflow->tf_thrd_fops, FLOW_MASTER);
1958 }
1959
1960 /*
1961 * Fills in the attributes for a newly allocated flowop
1962 */
1963 static void
parser_flowop_get_attrs(cmd_t * cmd,flowop_t * flowop)1964 parser_flowop_get_attrs(cmd_t *cmd, flowop_t *flowop)
1965 {
1966 attr_t *attr;
1967
1968 /* Get the filename from attribute */
1969 if ((attr = get_attr(cmd, FSA_FILENAME))) {
1970 flowop->fo_filename = attr->attr_avd;
1971 if (flowop->fo_filename == NULL) {
1972 filebench_log(LOG_ERROR,
1973 "define flowop: no filename specfied");
1974 filebench_shutdown(1);
1975 }
1976 } else {
1977 /* no filename attribute specified */
1978 flowop->fo_filename = NULL;
1979 }
1980
1981 /* Get the iosize of the op */
1982 if ((attr = get_attr(cmd, FSA_IOSIZE)))
1983 flowop->fo_iosize = attr->attr_avd;
1984 else
1985 flowop->fo_iosize = avd_int_alloc(0);
1986
1987 /* Get the working set size of the op */
1988 if ((attr = get_attr(cmd, FSA_WSS)))
1989 flowop->fo_wss = attr->attr_avd;
1990 else
1991 flowop->fo_wss = avd_int_alloc(0);
1992
1993 /* Random I/O? */
1994 if ((attr = get_attr(cmd, FSA_RANDOM)))
1995 flowop->fo_random = attr->attr_avd;
1996 else
1997 flowop->fo_random = avd_bool_alloc(FALSE);
1998
1999 /* Sync I/O? */
2000 if ((attr = get_attr(cmd, FSA_DSYNC)))
2001 flowop->fo_dsync = attr->attr_avd;
2002 else
2003 flowop->fo_dsync = avd_bool_alloc(FALSE);
2004
2005 /* Target, for wakeup etc */
2006 if ((attr = get_attr(cmd, FSA_TARGET)))
2007 (void) strcpy(flowop->fo_targetname,
2008 avd_get_str(attr->attr_avd));
2009
2010 /* Value */
2011 if ((attr = get_attr(cmd, FSA_VALUE)))
2012 flowop->fo_value = attr->attr_avd;
2013 else
2014 flowop->fo_value = avd_int_alloc(0);
2015
2016 /* FD */
2017 if ((attr = get_attr(cmd, FSA_FD))) {
2018 flowop->fo_fdnumber = avd_get_int(attr->attr_avd);
2019 if (flowop->fo_filename != NULL)
2020 filebench_log(LOG_DEBUG_SCRIPT, "It is not "
2021 "advisable to supply both an fd number "
2022 "and a fileset name in most cases");
2023 }
2024
2025 /* Rotatefd? */
2026 if ((attr = get_attr(cmd, FSA_ROTATEFD)))
2027 flowop->fo_rotatefd = attr->attr_avd;
2028 else
2029 flowop->fo_rotatefd = avd_bool_alloc(FALSE);
2030
2031 /* SRC FD, for copies etc... */
2032 if ((attr = get_attr(cmd, FSA_SRCFD)))
2033 flowop->fo_srcfdnumber = avd_get_int(attr->attr_avd);
2034
2035 /* Blocking operation? */
2036 if ((attr = get_attr(cmd, FSA_BLOCKING)))
2037 flowop->fo_blocking = attr->attr_avd;
2038 else
2039 flowop->fo_blocking = avd_bool_alloc(FALSE);
2040
2041 /* Direct I/O Operation */
2042 if ((attr = get_attr(cmd, FSA_DIRECTIO)))
2043 flowop->fo_directio = attr->attr_avd;
2044 else
2045 flowop->fo_directio = avd_bool_alloc(FALSE);
2046
2047 /* Highwater mark */
2048 if ((attr = get_attr(cmd, FSA_HIGHWATER))) {
2049 flowop->fo_highwater = attr->attr_avd;
2050 if (AVD_IS_RANDOM(attr->attr_avd)) {
2051 filebench_log(LOG_ERROR,
2052 "define flowop: Highwater attr cannot be random");
2053 filebench_shutdown(1);
2054 }
2055 } else {
2056 flowop->fo_highwater = avd_int_alloc(1);
2057 }
2058
2059 /* find file or leaf directory by index number */
2060 if ((attr = get_attr(cmd, FSA_INDEXED)))
2061 flowop->fo_fileindex = attr->attr_avd;
2062 else
2063 flowop->fo_fileindex = NULL;
2064
2065 /* Read Ahead Diable */
2066 if ((attr = get_attr(cmd, FSA_NOREADAHEAD)))
2067 flowop->fo_noreadahead = attr->attr_avd;
2068 else
2069 flowop->fo_noreadahead = avd_bool_alloc(FALSE);
2070
2071
2072 }
2073
2074 /*
2075 * defines the FLOW_MASTER flowops within a FLOW_MASTER instance of
2076 * a composit flowop. Default attributes from the FLOW_INNER_DEF instances
2077 * of the composit flowop's inner flowops are used if set. Otherwise
2078 * default attributes from the FLOW_MASTER instance of the composit flowop
2079 * are used, which may include defaults from the original FLOW_DEFINITION
2080 * of the composit flowop.
2081 */
2082 static void
parser_inner_flowop_define(threadflow_t * thread,flowop_t * comp0_flow,flowop_t * comp_mstr_flow)2083 parser_inner_flowop_define(threadflow_t *thread, flowop_t *comp0_flow,
2084 flowop_t *comp_mstr_flow)
2085 {
2086 flowop_t *inner_flowtype, *inner_flowop;
2087
2088 /* follow flowop list, creating composit names */
2089 inner_flowtype = comp0_flow->fo_comp_fops;
2090 comp_mstr_flow->fo_comp_fops = NULL;
2091
2092 while (inner_flowtype) {
2093 char fullname[MAXPATHLEN];
2094
2095 /* create composite_name.name for new flowop */
2096 snprintf(fullname, MAXPATHLEN, "%s.%s",
2097 comp_mstr_flow->fo_name, inner_flowtype->fo_name);
2098
2099 if ((inner_flowop = flowop_define(thread, fullname,
2100 inner_flowtype, &comp_mstr_flow->fo_comp_fops,
2101 FLOW_MASTER, 0)) == NULL) {
2102 filebench_log(LOG_ERROR,
2103 "define flowop: Failed to instantiate flowop %s\n",
2104 fullname);
2105 filebench_shutdown(1);
2106 }
2107
2108 /* if applicable, update filename attribute */
2109 if (inner_flowop->fo_filename) {
2110 char *name;
2111
2112 /* fix up avd_t */
2113 avd_update(&inner_flowop->fo_filename,
2114 comp_mstr_flow->fo_lvar_list);
2115
2116 /* see if ready to get the file or fileset */
2117 name = avd_get_str(inner_flowop->fo_filename);
2118 if (name) {
2119
2120 inner_flowop->fo_fileset = fileset_find(name);
2121
2122 if (inner_flowop->fo_fileset == NULL) {
2123 filebench_log(LOG_ERROR,
2124 "inr flowop %s: file %s not found",
2125 inner_flowop->fo_name, name);
2126 filebench_shutdown(1);
2127 }
2128 }
2129 }
2130
2131 /* update attributes from local variables */
2132 avd_update(&inner_flowop->fo_iters,
2133 comp_mstr_flow->fo_lvar_list);
2134
2135 /* if the inner flowop is a composit flowop, recurse */
2136 if (inner_flowtype->fo_type == FLOW_TYPE_COMPOSITE) {
2137 var_t *newlvar, *proto_lvars, *lvar_ptr;
2138
2139 proto_lvars = inner_flowop->fo_lvar_list;
2140 inner_flowop->fo_lvar_list = 0;
2141
2142 for (lvar_ptr = inner_flowtype->fo_lvar_list; lvar_ptr;
2143 lvar_ptr = lvar_ptr->var_next) {
2144
2145 if ((newlvar = var_lvar_alloc_local(
2146 lvar_ptr->var_name)) != NULL) {
2147
2148 add_lvar_to_list(newlvar,
2149 &inner_flowop->fo_lvar_list);
2150
2151 var_update_comp_lvars(newlvar,
2152 proto_lvars,
2153 comp_mstr_flow->fo_lvar_list);
2154 }
2155 }
2156
2157 parser_inner_flowop_define(thread,
2158 inner_flowtype,
2159 inner_flowop);
2160
2161 inner_flowtype = inner_flowtype->fo_exec_next;
2162 continue;
2163 }
2164
2165 avd_update(&inner_flowop->fo_iosize,
2166 comp_mstr_flow->fo_lvar_list);
2167 avd_update(&inner_flowop->fo_wss,
2168 comp_mstr_flow->fo_lvar_list);
2169 avd_update(&inner_flowop->fo_iters,
2170 comp_mstr_flow->fo_lvar_list);
2171 avd_update(&inner_flowop->fo_value,
2172 comp_mstr_flow->fo_lvar_list);
2173 avd_update(&inner_flowop->fo_random,
2174 comp_mstr_flow->fo_lvar_list);
2175 avd_update(&inner_flowop->fo_dsync,
2176 comp_mstr_flow->fo_lvar_list);
2177 avd_update(&inner_flowop->fo_rotatefd,
2178 comp_mstr_flow->fo_lvar_list);
2179 avd_update(&inner_flowop->fo_blocking,
2180 comp_mstr_flow->fo_lvar_list);
2181 avd_update(&inner_flowop->fo_directio,
2182 comp_mstr_flow->fo_lvar_list);
2183 avd_update(&inner_flowop->fo_highwater,
2184 comp_mstr_flow->fo_lvar_list);
2185
2186 inner_flowtype = inner_flowtype->fo_exec_next;
2187 }
2188 }
2189
2190 /*
2191 * Calls flowop_define() to allocate a flowop with the supplied name.
2192 * The allocated flowop inherits attributes from a base flowop of the
2193 * same type. If the new flowop has a file or fileset attribute specified,
2194 * it must specify a defined fileobj or fileset or an error will be logged.
2195 * The new flowop may also have the following attributes set by
2196 * the program:
2197 * - file size (fo_iosize)
2198 * - working set size (fo_wss)
2199 * - do random io (fo_random)
2200 * - do synchronous io (fo_dsync)
2201 * - perform each operation multiple times before advancing (fo_iter)
2202 * - target name (fo_targetname)
2203 * - An integer value (fo_value)
2204 * - a file descriptor (fo_fd)
2205 * - specify to rotate file descriptors (fo_rotatefd)
2206 * - a source fd (fo_srcfdnumber)
2207 * - specify a blocking operation (fo_blocking)
2208 * - specify a highwater mark (fo_highwater)
2209 *
2210 * After all the supplied attributes are stored in their respective locations
2211 * in the flowop object, the flowop's init function is called. No errors are
2212 * returned, but the filebench run will be terminated if the flowtype is not
2213 * specified, a name for the new flowop is not supplied, the flowop_define
2214 * call fails, or a file or fileset name is supplied but the corresponding
2215 * fileobj or fileset cannot be located.
2216 */
2217 static void
parser_flowop_define(cmd_t * cmd,threadflow_t * thread,flowop_t ** flowoplist_hdp,int category)2218 parser_flowop_define(cmd_t *cmd, threadflow_t *thread,
2219 flowop_t **flowoplist_hdp, int category)
2220 {
2221 flowop_t *flowop, *flowop_type;
2222 char *type = (char *)cmd->cmd_name;
2223 char *name = NULL;
2224 attr_t *attr;
2225
2226 /* Get the inherited flowop */
2227 flowop_type = flowop_find(type);
2228 if (flowop_type == NULL) {
2229 filebench_log(LOG_ERROR,
2230 "define flowop: flowop type %s not found",
2231 type);
2232 filebench_shutdown(1);
2233 }
2234
2235 /* Get the name of the flowop */
2236 if ((attr = get_attr(cmd, FSA_NAME))) {
2237 name = avd_get_str(attr->attr_avd);
2238 } else {
2239 filebench_log(LOG_ERROR,
2240 "define flowop: flowop %s specifies no name",
2241 flowop_type->fo_name);
2242 filebench_shutdown(1);
2243 }
2244
2245 if ((flowop = flowop_define(thread, name,
2246 flowop_type, flowoplist_hdp, category, 0)) == NULL) {
2247 filebench_log(LOG_ERROR,
2248 "define flowop: Failed to instantiate flowop %s\n",
2249 cmd->cmd_name);
2250 filebench_shutdown(1);
2251 }
2252
2253 /* Iterations */
2254 if ((attr = get_attr(cmd, FSA_ITERS)))
2255 flowop->fo_iters = attr->attr_avd;
2256 else
2257 flowop->fo_iters = avd_int_alloc(1);
2258
2259
2260 /* if this is a use of a composit flowop, create inner FLOW MASTERS */
2261 if (flowop_type->fo_type == FLOW_TYPE_COMPOSITE) {
2262 get_attr_lvars(cmd, flowop);
2263 if (category == FLOW_MASTER)
2264 parser_inner_flowop_define(thread,
2265 flowop_type, flowop);
2266 }
2267 else {
2268 parser_flowop_get_attrs(cmd, flowop);
2269 }
2270 }
2271
2272 static void
parser_composite_flowop_define(cmd_t * cmd)2273 parser_composite_flowop_define(cmd_t *cmd)
2274 {
2275 flowop_t *flowop;
2276 cmd_t *inner_cmd;
2277 char *name = NULL;
2278 attr_t *attr;
2279
2280 /* Get the name of the flowop */
2281 if ((attr = get_attr(cmd, FSA_NAME))) {
2282 name = avd_get_str(attr->attr_avd);
2283 } else {
2284 filebench_log(LOG_ERROR,
2285 "define flowop: Composit flowop specifies no name");
2286
2287 filebench_shutdown(1);
2288 }
2289
2290 if ((flowop = flowop_new_composite_define(name)) == NULL) {
2291 filebench_log(LOG_ERROR,
2292 "define flowop: Failed to instantiate flowop %s\n",
2293 cmd->cmd_name);
2294 filebench_shutdown(1);
2295 }
2296
2297 /* place any local var_t variables on the flowop's local list */
2298 get_attr_lvars(cmd, flowop);
2299
2300 /* Iterations */
2301 if ((attr = get_attr(cmd, FSA_ITERS)))
2302 flowop->fo_iters = attr->attr_avd;
2303 else
2304 flowop->fo_iters = avd_int_alloc(1);
2305
2306 /* define inner flowops */
2307 for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
2308 inner_cmd = inner_cmd->cmd_next) {
2309 parser_flowop_define(inner_cmd, NULL,
2310 &flowop->fo_comp_fops, FLOW_INNER_DEF);
2311 }
2312 }
2313
2314
2315 /*
2316 * First, we verify that mandatory attributes - name and path - are specified.
2317 * Then allocate a fileset structure and setup its fields. Notice, at this
2318 * point we should not verify if AVD type makes sense, because AVD type can
2319 * change as variables are set to other values after fileset definition.
2320 */
2321 static fileset_t *
parser_fileset_define_common(cmd_t * cmd)2322 parser_fileset_define_common(cmd_t *cmd)
2323 {
2324 fileset_t *fileset;
2325 attr_t *attr;
2326 avd_t name;
2327 avd_t path;
2328
2329 attr = get_attr(cmd, FSA_NAME);
2330 if (attr)
2331 name = attr->attr_avd;
2332 else {
2333 filebench_log(LOG_ERROR, "file[set] specifies no name");
2334 return NULL;
2335 }
2336
2337 attr = get_attr(cmd, FSA_PATH);
2338 if (attr)
2339 path = attr->attr_avd;
2340 else {
2341 filebench_log(LOG_ERROR, "file[set] specifies no path");
2342 return NULL;
2343 }
2344
2345 fileset = fileset_define(name, path);
2346 if (!fileset) {
2347 filebench_log(LOG_ERROR, "failed to instantiate file[set] %s\n",
2348 avd_get_str(name));
2349 return NULL;
2350 }
2351
2352 attr = get_attr(cmd, FSA_PREALLOC);
2353 if (attr)
2354 fileset->fs_preallocpercent = attr->attr_avd;
2355 else
2356 fileset->fs_preallocpercent = avd_int_alloc(0);
2357
2358 attr = get_attr(cmd, FSA_PARALLOC);
2359 if (attr)
2360 fileset->fs_paralloc = attr->attr_avd;
2361 else
2362 fileset->fs_paralloc = avd_bool_alloc(FALSE);
2363
2364 attr = get_attr(cmd, FSA_READONLY);
2365 if (attr)
2366 fileset->fs_readonly = attr->attr_avd;
2367 else
2368 fileset->fs_readonly = avd_bool_alloc(FALSE);
2369
2370 attr = get_attr(cmd, FSA_WRITEONLY);
2371 if (attr)
2372 fileset->fs_writeonly = attr->attr_avd;
2373 else
2374 fileset->fs_writeonly = avd_bool_alloc(FALSE);
2375
2376 attr = get_attr(cmd, FSA_REUSE);
2377 if (attr)
2378 fileset->fs_reuse = attr->attr_avd;
2379 else
2380 fileset->fs_reuse = avd_bool_alloc(FALSE);
2381
2382 /* Should we check for files actual existance? */
2383 attr = get_attr(cmd, FSA_TRUSTTREE);
2384 if (attr )
2385 fileset->fs_trust_tree = attr->attr_avd;
2386 else
2387 fileset->fs_trust_tree = avd_bool_alloc(FALSE);
2388
2389 attr = get_attr(cmd, FSA_SIZE);
2390 if (attr)
2391 fileset->fs_size = attr->attr_avd;
2392 else
2393 fileset->fs_size = avd_int_alloc(1024);
2394
2395 return fileset;
2396 }
2397
2398 static void
parser_file_define(cmd_t * cmd)2399 parser_file_define(cmd_t *cmd)
2400 {
2401 fileset_t *fileset;
2402
2403 fileset = parser_fileset_define_common(cmd);
2404 if (!fileset) {
2405 filebench_log(LOG_ERROR, "failed to instantiate file");
2406 filebench_shutdown(1);
2407 return;
2408 }
2409
2410 /* fileset is emulating a single file */
2411 fileset->fs_attrs = FILESET_IS_FILE;
2412 fileset->fs_entries = avd_int_alloc(1);
2413 /* Set the mean dir width to more than 1 */
2414 fileset->fs_dirwidth = avd_int_alloc(10);
2415 fileset->fs_dirgamma = avd_int_alloc(0);
2416 fileset->fs_leafdirs = avd_int_alloc(0);
2417 }
2418
2419 static void
parser_fileset_define(cmd_t * cmd)2420 parser_fileset_define(cmd_t *cmd)
2421 {
2422 fileset_t *fileset;
2423 attr_t *attr;
2424
2425 fileset = parser_fileset_define_common(cmd);
2426 if (!fileset) {
2427 filebench_log(LOG_ERROR, "failed to instantiate fileset");
2428 filebench_shutdown(1);
2429 return;
2430 }
2431
2432 attr = get_attr(cmd, FSA_ENTRIES);
2433 if (attr)
2434 fileset->fs_entries = attr->attr_avd;
2435 else
2436 fileset->fs_entries = avd_int_alloc(0);
2437
2438 attr = get_attr(cmd, FSA_LEAFDIRS);
2439 if (attr)
2440 fileset->fs_leafdirs = attr->attr_avd;
2441 else
2442 fileset->fs_leafdirs = avd_int_alloc(0);
2443
2444 attr = get_attr(cmd, FSA_DIRWIDTH);
2445 if (attr)
2446 fileset->fs_dirwidth = attr->attr_avd;
2447 else {
2448 filebench_log(LOG_ERROR, "Fileset has no directory width");
2449 fileset->fs_dirwidth = avd_int_alloc(0);
2450 }
2451
2452 attr = get_attr(cmd, FSA_DIRDEPTHRV);
2453 if (attr)
2454 fileset->fs_dirdepthrv = attr->attr_avd;
2455 else
2456 fileset->fs_dirdepthrv = NULL;
2457
2458 attr = get_attr(cmd, FSA_DIRGAMMA);
2459 if (attr)
2460 fileset->fs_dirgamma = attr->attr_avd;
2461 else
2462 fileset->fs_dirgamma = avd_int_alloc(1500);
2463 }
2464
2465 /*
2466 * Calls fileset_createsets() to populate all filesets and create all
2467 * associated, initially existant, files and subdirectories.
2468 * If errors are encountered, calls filebench_shutdown() to exit Filebench.
2469 */
2470 static void
parser_fileset_create(cmd_t * cmd)2471 parser_fileset_create(cmd_t *cmd)
2472 {
2473 int ret;
2474
2475 ret = fileset_createsets();
2476 if (ret) {
2477 filebench_log(LOG_ERROR, "Failed to create filesets");
2478 filebench_shutdown(1);
2479 }
2480 }
2481
2482 /*
2483 * Ends filebench run after first destoring any interprocess
2484 * shared memory. The call to filebench_shutdown()
2485 * also causes filebench to exit.
2486 */
2487 static void
parser_filebench_shutdown(cmd_t * cmd)2488 parser_filebench_shutdown(cmd_t *cmd)
2489 {
2490 int f_abort = filebench_shm->shm_f_abort;
2491
2492 ipc_fini();
2493
2494 if (f_abort == FILEBENCH_ABORT_ERROR)
2495 filebench_shutdown(1);
2496 else
2497 filebench_shutdown(0);
2498 }
2499
2500 /*
2501 * This is used for timing runs. Pauses the master thread in one second
2502 * intervals until the supplied ptime runs out or the f_abort flag
2503 * is raised. If given a time of zero, it will pause until f_abort is raised.
2504 */
2505 static int
parser_pause(int ptime)2506 parser_pause(int ptime)
2507 {
2508 int timeslept = 0;
2509
2510 if (ptime) {
2511 while (timeslept < ptime) {
2512 (void) sleep(1);
2513 timeslept++;
2514 if (filebench_shm->shm_f_abort)
2515 break;
2516 }
2517 } else {
2518 /* initial runtime of 0 means run till abort */
2519 /* CONSTCOND */
2520 while (1) {
2521 (void) sleep(1);
2522 timeslept++;
2523 if (filebench_shm->shm_f_abort)
2524 break;
2525 }
2526 }
2527
2528 return (timeslept);
2529 }
2530
2531 #define TIMED_RUNTIME_DEFAULT 60 /* In seconds */
2532 #define PERIOD_DEFAULT 10 /* In seconds */
2533
2534 /*
2535 * Do a file bench run. Calls routines to create file sets, files, and
2536 * processes. It resets the statistics counters, then sleeps for the runtime
2537 * passed as an argument to it on the command line in 1 second increments.
2538 * When it is finished sleeping, it collects a snapshot of the statistics
2539 * and ends the run.
2540 */
2541 static void
parser_run(cmd_t * cmd)2542 parser_run(cmd_t *cmd)
2543 {
2544 int runtime;
2545 int timeslept;
2546
2547 runtime = cmd->cmd_qty;
2548
2549 parser_fileset_create(cmd);
2550 proc_create();
2551
2552 /* check for startup errors */
2553 if (filebench_shm->shm_f_abort)
2554 return;
2555
2556 filebench_log(LOG_INFO, "Running...");
2557 stats_clear();
2558
2559 /* If it is a timed mode and timeout is not specified use default */
2560 if (filebench_shm->shm_rmode == FILEBENCH_MODE_TIMEOUT && !runtime)
2561 runtime = TIMED_RUNTIME_DEFAULT;
2562
2563 timeslept = parser_pause(runtime);
2564
2565 filebench_log(LOG_INFO, "Run took %d seconds...", timeslept);
2566 stats_snap();
2567 proc_shutdown();
2568 parser_filebench_shutdown((cmd_t *)0);
2569 }
2570
2571 static void
parser_psrun(cmd_t * cmd)2572 parser_psrun(cmd_t *cmd)
2573 {
2574 int runtime;
2575 int period;
2576 int timeslept = 0;
2577 int reset_stats = 0;
2578
2579 runtime = cmd->cmd_qty;
2580
2581 /*
2582 * If period is negative then
2583 * we want to reset statistics
2584 * at the end of the every period
2585 */
2586 if (cmd->cmd_qty1 < 0) {
2587 period = -cmd->cmd_qty1;
2588 reset_stats = 1;
2589 } else if (cmd->cmd_qty1 > 0) {
2590 period = cmd->cmd_qty1;
2591 reset_stats = 0;
2592 } else { /* (cmd->cmd_qty1) == 0 */
2593 period = PERIOD_DEFAULT;
2594 reset_stats = 0;
2595 }
2596
2597 parser_fileset_create(cmd);
2598 proc_create();
2599
2600 /* check for startup errors */
2601 if (filebench_shm->shm_f_abort)
2602 return;
2603
2604 filebench_log(LOG_INFO, "Running...");
2605 stats_clear();
2606
2607 /* If it is a timed mode and timeout is not specified use default */
2608 if (filebench_shm->shm_rmode == FILEBENCH_MODE_TIMEOUT && !runtime)
2609 runtime = TIMED_RUNTIME_DEFAULT;
2610
2611 while (1) {
2612 /* sleep the remaining time if a period is smaller */
2613 if (filebench_shm->shm_rmode == FILEBENCH_MODE_TIMEOUT)
2614 period = period > (runtime - timeslept) ?
2615 (runtime - timeslept) : period;
2616
2617 timeslept += parser_pause(period);
2618
2619 if (filebench_shm->shm_f_abort)
2620 break;
2621
2622 if (filebench_shm->shm_rmode == FILEBENCH_MODE_TIMEOUT &&
2623 timeslept >= runtime)
2624 break;
2625
2626 stats_snap();
2627
2628 if (reset_stats)
2629 stats_clear();
2630 }
2631
2632 filebench_log(LOG_INFO, "Run took %d seconds...", timeslept);
2633 stats_snap();
2634 proc_shutdown();
2635 parser_filebench_shutdown((cmd_t *)0);
2636 }
2637
2638 /*
2639 * Similar to parser_run, but gets the sleep time from a variable
2640 * whose name is supplied as an argument to the command.
2641 */
2642 static void
parser_run_variable(cmd_t * cmd)2643 parser_run_variable(cmd_t *cmd)
2644 {
2645 avd_t integer = avd_var_alloc(cmd->cmd_tgt1);
2646 int runtime;
2647 int timeslept;
2648
2649 if (integer == NULL) {
2650 filebench_log(LOG_ERROR, "Unknown variable %s",
2651 cmd->cmd_tgt1);
2652 return;
2653 }
2654
2655 runtime = avd_get_int(integer);
2656
2657 parser_fileset_create(cmd);
2658 proc_create();
2659
2660 /* check for startup errors */
2661 if (filebench_shm->shm_f_abort)
2662 return;
2663
2664 filebench_log(LOG_INFO, "Running...");
2665 stats_clear();
2666
2667 /* If it is a timed mode and timeout is not specified use default */
2668 if (filebench_shm->shm_rmode == FILEBENCH_MODE_TIMEOUT && !runtime)
2669 runtime = TIMED_RUNTIME_DEFAULT;
2670
2671 timeslept = parser_pause(runtime);
2672
2673 filebench_log(LOG_INFO, "Run took %d seconds...", timeslept);
2674 stats_snap();
2675 proc_shutdown();
2676 parser_filebench_shutdown((cmd_t *)0);
2677 }
2678
2679 /*
2680 * Establishes multi-client synchronization socket with synch server.
2681 */
2682 static void
parser_enable_mc(cmd_t * cmd)2683 parser_enable_mc(cmd_t *cmd)
2684 {
2685 attr_t *attr;
2686 char *master;
2687 char *client;
2688
2689 if ((attr = get_attr(cmd, FSA_MASTER))) {
2690 master = avd_get_str(attr->attr_avd);
2691 } else {
2692 filebench_log(LOG_ERROR,
2693 "enable multi: no master specified");
2694 return;
2695 }
2696
2697 if ((attr = get_attr(cmd, FSA_CLIENT))) {
2698 client = avd_get_str(attr->attr_avd);
2699 } else {
2700 filebench_log(LOG_ERROR,
2701 "enable multi: no client specified");
2702 return;
2703 }
2704
2705 mc_sync_open_sock(master, 8001, client);
2706 }
2707
2708 /*
2709 * Exchanges multi-client synchronization message with synch server.
2710 */
2711 static void
parser_domultisync(cmd_t * cmd)2712 parser_domultisync(cmd_t *cmd)
2713 {
2714 attr_t *attr;
2715 fbint_t value;
2716
2717 if ((attr = get_attr(cmd, FSA_VALUE)))
2718 value = avd_get_int(attr->attr_avd);
2719 else
2720 value = 1;
2721
2722 mc_sync_synchronize((int)value);
2723 }
2724
2725 /*
2726 * Sleeps for cmd->cmd_qty seconds, one second at a time.
2727 */
2728 static void
parser_sleep(cmd_t * cmd)2729 parser_sleep(cmd_t *cmd)
2730 {
2731 int sleeptime;
2732 int timeslept;
2733
2734 /* check for startup errors */
2735 if (filebench_shm->shm_f_abort)
2736 return;
2737
2738 sleeptime = cmd->cmd_qty;
2739 filebench_log(LOG_INFO, "Sleeping...");
2740
2741 timeslept = parser_pause(sleeptime);
2742
2743 filebench_log(LOG_INFO, "Slept for %d seconds...", timeslept);
2744 }
2745
2746 /*
2747 * Same as parser_sleep, except the sleep time is obtained from a variable
2748 * whose name is passed to it as an argument on the command line.
2749 */
2750 static void
parser_sleep_variable(cmd_t * cmd)2751 parser_sleep_variable(cmd_t *cmd)
2752 {
2753 avd_t integer = avd_var_alloc(cmd->cmd_tgt1);
2754 int sleeptime;
2755 int timeslept;
2756
2757 if (integer == NULL) {
2758 filebench_log(LOG_ERROR, "Unknown variable %s",
2759 cmd->cmd_tgt1);
2760 return;
2761 }
2762
2763 sleeptime = avd_get_int(integer);
2764
2765 /* check for startup errors */
2766 if (filebench_shm->shm_f_abort)
2767 return;
2768
2769 filebench_log(LOG_INFO, "Running...");
2770
2771 timeslept = parser_pause(sleeptime);
2772
2773 filebench_log(LOG_INFO, "Run took %d seconds...", timeslept);
2774 }
2775
2776 /*
2777 * Launches a shell to run the unix command supplied in the argument.
2778 * The command should be enclosed in quotes, as in:
2779 * system "rm xyz"
2780 * which would run the "rm" utility to delete the file "xyz".
2781 */
2782 static void
parser_system(cmd_t * cmd)2783 parser_system(cmd_t *cmd)
2784 {
2785 char *string;
2786
2787 if (!cmd->cmd_param_list)
2788 return;
2789
2790 string = parser_list2string(cmd->cmd_param_list);
2791
2792 if (!string)
2793 return;
2794
2795 filebench_log(LOG_VERBOSE, "Running '%s'", string);
2796
2797 if (system(string) < 0) {
2798 filebench_log(LOG_ERROR,
2799 "system exec failed: %s",
2800 strerror(errno));
2801 free(string);
2802 filebench_shutdown(1);
2803 }
2804
2805 free(string);
2806 }
2807
2808 /*
2809 * Echos string supplied with command to the log.
2810 */
2811 static void
parser_echo(cmd_t * cmd)2812 parser_echo(cmd_t *cmd)
2813 {
2814 char *string;
2815
2816 if (cmd->cmd_param_list == NULL)
2817 return;
2818
2819 string = parser_list2string(cmd->cmd_param_list);
2820
2821 if (string == NULL)
2822 return;
2823
2824 filebench_log(LOG_INFO, "%s", string);
2825 }
2826
2827 /*
2828 * Prints out the version of Filebench.
2829 */
2830 static void
parser_version(cmd_t * cmd)2831 parser_version(cmd_t *cmd)
2832 {
2833 filebench_log(LOG_INFO, "Filebench Version: %s", FILEBENCH_VERSION);
2834 }
2835
2836 static void
parser_enable_lathist(cmd_t * cmd)2837 parser_enable_lathist(cmd_t *cmd)
2838 {
2839 filebench_shm->lathist_enabled = 1;
2840 filebench_log(LOG_INFO, "Latency histogram enabled");
2841 }
2842
2843 /*
2844 * define a random variable and initialize the distribution parameters
2845 */
2846 static void
parser_var_assign_random(char * name,cmd_t * cmd)2847 parser_var_assign_random(char *name, cmd_t *cmd)
2848 {
2849 randdist_t *rndp;
2850 attr_t *attr;
2851
2852 rndp = randdist_alloc();
2853 if (!rndp) {
2854 filebench_log(LOG_ERROR,
2855 "failed to alloc random distribution object\n");
2856 return;
2857 }
2858
2859 rndp->rnd_type = 0;
2860
2861 /* Get the source of the random numbers */
2862 if ((attr = get_attr(cmd, FSA_RANDSRC))) {
2863 int randsrc = (int)avd_get_int(attr->attr_avd);
2864
2865 switch (randsrc) {
2866 case FSV_URAND:
2867 rndp->rnd_type |= RAND_SRC_URANDOM;
2868 break;
2869 case FSV_RAND48:
2870 rndp->rnd_type |= RAND_SRC_GENERATOR;
2871 break;
2872 }
2873 } else {
2874 /* default to rand48 random number generator */
2875 rndp->rnd_type |= RAND_SRC_GENERATOR;
2876 }
2877
2878 /* Get the min value of the random distribution */
2879 if ((attr = get_attr(cmd, FSA_MIN)))
2880 rndp->rnd_min = attr->attr_avd;
2881 else
2882 rndp->rnd_min = avd_int_alloc(0);
2883
2884 /* Get the roundoff value for the random distribution */
2885 if ((attr = get_attr(cmd, FSA_ROUND)))
2886 rndp->rnd_round = attr->attr_avd;
2887 else
2888 rndp->rnd_round = avd_int_alloc(0);
2889
2890 /* Get a tablular probablility distribution if there is one */
2891 if ((attr = get_attr(cmd, FSA_RANDTABLE))) {
2892 rndp->rnd_probtabs = (probtabent_t *)(attr->attr_obj);
2893 rndp->rnd_type |= RAND_TYPE_TABLE;
2894 } else {
2895 rndp->rnd_probtabs = NULL;
2896 }
2897
2898 /* Get the type for the random variable */
2899 if ((attr = get_attr(cmd, FSA_TYPE))) {
2900 int disttype = (int)avd_get_int(attr->attr_avd);
2901
2902 switch (disttype) {
2903 case FSV_RANDUNI:
2904 rndp->rnd_type |= RAND_TYPE_UNIFORM;
2905 break;
2906 case FSA_RANDGAMMA:
2907 rndp->rnd_type |= RAND_TYPE_GAMMA;
2908 break;
2909 case FSV_RANDTAB:
2910 filebench_log(LOG_ERROR,
2911 "Table distribution type without prob table");
2912 break;
2913 }
2914 } else {
2915 /* default to gamma distribution type */
2916 rndp->rnd_type |= RAND_TYPE_GAMMA;
2917 }
2918
2919 /* Get the seed for the random variable */
2920 if ((attr = get_attr(cmd, FSA_RANDSEED)))
2921 rndp->rnd_seed = attr->attr_avd;
2922 else
2923 rndp->rnd_seed = avd_int_alloc(0);
2924
2925 /* Get the gamma value of the random distribution */
2926 if ((attr = get_attr(cmd, FSA_RANDGAMMA)))
2927 rndp->rnd_gamma = attr->attr_avd;
2928 else
2929 rndp->rnd_gamma = avd_int_alloc(1500);
2930
2931 /* Get the mean value of the random distribution */
2932 if ((attr = get_attr(cmd, FSA_RANDMEAN))) {
2933 rndp->rnd_mean = attr->attr_avd;
2934 } else if ((rndp->rnd_type & RAND_TYPE_MASK) == RAND_TYPE_GAMMA) {
2935 rndp->rnd_mean = NULL;
2936 } else {
2937 rndp->rnd_mean = avd_int_alloc(0);
2938 }
2939
2940 var_assign_random(name, rndp);
2941
2942 randdist_init(rndp);
2943 }
2944
2945 /*
2946 * alloc_cmd() allocates the required resources for a cmd_t. On failure, a
2947 * filebench_log is issued and NULL is returned.
2948 */
2949 static cmd_t *
alloc_cmd(void)2950 alloc_cmd(void)
2951 {
2952 cmd_t *cmd;
2953
2954 cmd = malloc(sizeof(*cmd));
2955 if (!cmd) {
2956 filebench_log(LOG_ERROR, "Alloc cmd failed");
2957 return NULL;
2958 }
2959
2960 memset(cmd, 0, sizeof (cmd_t));
2961
2962 return cmd;
2963 }
2964
2965 /*
2966 * Allocates an attr_t structure and zeros it. Returns NULL on failure, or
2967 * a pointer to the attr_t.
2968 */
2969 static attr_t *
alloc_attr(void)2970 alloc_attr(void)
2971 {
2972 attr_t *attr;
2973
2974 attr = malloc(sizeof(*attr));
2975 if (!attr)
2976 return (NULL);
2977
2978 (void) memset(attr, 0, sizeof(*attr));
2979
2980 return (attr);
2981 }
2982
2983 /*
2984 * Allocates a probtabent_t structure and zeros it. Returns NULL on failure, or
2985 * a pointer to the probtabent_t.
2986 */
2987 static probtabent_t *
alloc_probtabent(void)2988 alloc_probtabent(void)
2989 {
2990 probtabent_t *rte;
2991
2992 if ((rte = malloc(sizeof (probtabent_t))) == NULL) {
2993 return (NULL);
2994 }
2995
2996 (void) memset(rte, 0, sizeof (probtabent_t));
2997 return (rte);
2998 }
2999
3000 /*
3001 * Allocates an attr_t structure and puts the supplied var_t into
3002 * its attr_avd location, and sets its name to FSA_LVAR_ASSIGN
3003 */
3004 static attr_t *
alloc_lvar_attr(var_t * var)3005 alloc_lvar_attr(var_t *var)
3006 {
3007 attr_t *attr;
3008
3009 if ((attr = alloc_attr()) == NULL)
3010 return (NULL);
3011
3012 attr->attr_name = FSA_LVAR_ASSIGN;
3013 attr->attr_avd = (avd_t)var;
3014
3015 return (attr);
3016 }
3017
3018 /*
3019 * Searches the attribute list for the command for the named attribute type.
3020 * The attribute list is created by the parser from the list of attributes
3021 * supplied with certain commands, such as the define and flowop commands.
3022 * Returns a pointer to the attribute structure if the named attribute is
3023 * found, otherwise returns NULL. If the attribute includes a parameter list,
3024 * the list is converted to a string and stored in the attr_avd field of
3025 * the returned attr_t struct.
3026 */
3027 static attr_t *
get_attr(cmd_t * cmd,int64_t name)3028 get_attr(cmd_t *cmd, int64_t name)
3029 {
3030 attr_t *attr;
3031 attr_t *rtn = NULL;
3032
3033 for (attr = cmd->cmd_attr_list; attr != NULL;
3034 attr = attr->attr_next) {
3035
3036 filebench_log(LOG_DEBUG_IMPL,
3037 "attr %d = %d %llx?",
3038 attr->attr_name,
3039 name,
3040 attr->attr_avd);
3041
3042 if (attr->attr_name == name)
3043 rtn = attr;
3044 }
3045
3046 return rtn;
3047 }
3048
3049 /*
3050 * removes the newly allocated local var from the shared local var
3051 * list, then puts it at the head of the private local var list
3052 * supplied as the second argument.
3053 */
3054 static void
add_lvar_to_list(var_t * newlvar,var_t ** lvar_list)3055 add_lvar_to_list(var_t *newlvar, var_t **lvar_list)
3056 {
3057 var_t *prev;
3058
3059 /* remove from shared local list, if there */
3060 if (newlvar == filebench_shm->shm_var_loc_list) {
3061 /* on top of list, just grap */
3062 filebench_shm->shm_var_loc_list = newlvar->var_next;
3063 } else {
3064 /* find newvar on list and remove */
3065 for (prev = filebench_shm->shm_var_loc_list; prev;
3066 prev = prev->var_next) {
3067 if (prev->var_next == newlvar)
3068 prev->var_next = newlvar->var_next;
3069 }
3070 }
3071 newlvar->var_next = NULL;
3072
3073 /* add to flowop private local list at head */
3074 newlvar->var_next = *lvar_list;
3075 *lvar_list = newlvar;
3076 }
3077
3078 /*
3079 * Searches the attribute list for the command for any allocated local
3080 * variables. The attribute list is created by the parser from the list of
3081 * attributes supplied with certain commands, such as the define and flowop
3082 * commands. Places all found local vars onto the flowop's local variable
3083 * list.
3084 */
3085 static void
get_attr_lvars(cmd_t * cmd,flowop_t * flowop)3086 get_attr_lvars(cmd_t *cmd, flowop_t *flowop)
3087 {
3088 attr_t *attr;
3089 var_t *orig_lvar_list;
3090
3091 /* save the local var list */
3092 orig_lvar_list = flowop->fo_lvar_list;
3093
3094 for (attr = cmd->cmd_attr_list; attr != NULL;
3095 attr = attr->attr_next) {
3096
3097 if (attr->attr_name == FSA_LVAR_ASSIGN) {
3098 var_t *newvar;
3099
3100 if ((newvar = (var_t *)attr->attr_avd) == NULL)
3101 continue;
3102
3103 add_lvar_to_list(newvar, &flowop->fo_lvar_list);
3104 var_update_comp_lvars(newvar, orig_lvar_list, NULL);
3105 }
3106 }
3107 }
3108
3109 /*
3110 * Allocates memory for a list_t structure, initializes it to zero, and
3111 * returns a pointer to it. On failure, returns NULL.
3112 */
3113 static list_t *
alloc_list()3114 alloc_list()
3115 {
3116 list_t *list;
3117
3118 if ((list = malloc(sizeof (list_t))) == NULL) {
3119 return (NULL);
3120 }
3121
3122 (void) memset(list, 0, sizeof (list_t));
3123 return (list);
3124 }
3125
3126 /*
3127 * Define a custom variable and validate its parameters.
3128 * TODO: Clean up state when things go wrong.
3129 */
3130 static void
parser_var_assign_custom(char * name,cmd_t * cmd)3131 parser_var_assign_custom(char *name, cmd_t *cmd)
3132 {
3133 cvar_t *cvar;
3134 attr_t *attr;
3135 char *type;
3136 char *parameters;
3137 int ret;
3138
3139 attr = get_attr(cmd, FSA_TYPE);
3140 if (attr)
3141 type = avd_get_str(attr->attr_avd);
3142 else {
3143 filebench_log(LOG_ERROR, "define cvar: no type specified");
3144 filebench_shutdown(1);
3145 return;
3146 }
3147
3148 cvar = cvar_alloc();
3149 if (!cvar) {
3150 filebench_log(LOG_ERROR, "Failed to allocate custom variable");
3151 filebench_shutdown(1);
3152 return;
3153 }
3154
3155 /* Initialize the custom variable mutex. */
3156 (void) pthread_mutex_init(&cvar->cvar_lock,
3157 ipc_mutexattr(IPC_MUTEX_NORMAL));
3158
3159 /* Get the min, max and round values for the custom variable. */
3160 if ((attr = get_attr(cmd, FSA_MIN)))
3161 cvar->min = avd_get_dbl(attr->attr_avd);
3162 else
3163 cvar->min = DBL_MIN;
3164
3165 if ((attr = get_attr(cmd, FSA_MAX)))
3166 cvar->max = avd_get_dbl(attr->attr_avd);
3167 else
3168 cvar->max = DBL_MAX;
3169
3170 if ((attr = get_attr(cmd, FSA_ROUND)))
3171 cvar->round = avd_get_dbl(attr->attr_avd);
3172 else
3173 cvar->round = 0;
3174
3175 attr = get_attr(cmd, FSA_PARAMETERS);
3176 if (attr)
3177 parameters = avd_get_str(attr->attr_avd);
3178 else
3179 parameters = NULL;
3180
3181 ret = init_cvar_handle(cvar, type, parameters);
3182 if (ret) {
3183 filebench_log(LOG_FATAL, "define cvar: failed for custom variable %s",
3184 name);
3185 filebench_shutdown(1);
3186 return;
3187 }
3188
3189 var_assign_custom(name, cvar);
3190 }
3191