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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Portions Copyright 2008 Denis Cheng
26 */
27
28 %{
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <locale.h>
37 #include <sys/utsname.h>
38 #include <sys/statvfs.h>
39 #ifdef HAVE_STDINT_H
40 #include <stdint.h>
41 #endif
42 #include <fcntl.h>
43 #include <sys/mman.h>
44 #include <sys/wait.h>
45 #ifdef HAVE_LIBTECLA
46 #include <libtecla.h>
47 #endif
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 #ifdef HAVE_LIBTECLA
55 #include "auto_comp.h"
56 #endif
57 #include "multi_client_sync.h"
58
59 int dofile = FS_FALSE;
60 static const char cmdname[] = "filebench";
61 static const char cmd_options[] = "pa:f:hi:s:m:";
62 static void usage(int);
63
64 static cmd_t *cmd = NULL; /* Command being processed */
65 #ifdef HAVE_LIBTECLA
66 static GetLine *gl; /* GetLine resource object */
67 #endif
68
69 char *execname;
70 char *fbbasepath = FILEBENCHDIR;
71 char *fscriptname;
72 int noproc = 0;
73 var_t *var_list = NULL;
74 pidlist_t *pidlist = NULL;
75 char *cwd = NULL;
76 FILE *parentscript = NULL;
77
78 static int filecreate_done = 0;
79
80 /* yacc externals */
81 extern FILE *yyin;
82 extern int yydebug;
83 extern void yyerror(char *s);
84
85 /* utilities */
86 static void terminate(void);
87 static cmd_t *alloc_cmd(void);
88 static attr_t *alloc_attr(void);
89 static attr_t *alloc_lvar_attr(var_t *var);
90 static attr_t *get_attr(cmd_t *cmd, int64_t name);
91 static attr_t *get_attr_fileset(cmd_t *cmd, int64_t name);
92 static attr_t *get_attr_integer(cmd_t *cmd, int64_t name);
93 static attr_t *get_attr_bool(cmd_t *cmd, int64_t name);
94 static void get_attr_lvars(cmd_t *cmd, flowop_t *flowop);
95 static var_t *alloc_var(void);
96 static var_t *get_var(cmd_t *cmd, int64_t name);
97 static list_t *alloc_list();
98 static probtabent_t *alloc_probtabent(void);
99 static void add_lvar_to_list(var_t *newlvar, var_t **lvar_list);
100
101 /* Info Commands */
102 static void parser_list(cmd_t *);
103 static void parser_flowop_list(cmd_t *);
104
105 /* Define Commands */
106 static void parser_proc_define(cmd_t *);
107 static void parser_thread_define(cmd_t *, procflow_t *, int instances);
108 static void parser_flowop_define(cmd_t *, threadflow_t *, flowop_t **, int);
109 static void parser_file_define(cmd_t *);
110 static void parser_fileset_define(cmd_t *);
111 static void parser_randvar_define(cmd_t *);
112 static void parser_randvar_set(cmd_t *);
113 static void parser_composite_flowop_define(cmd_t *);
114
115 /* Create Commands */
116 static void parser_proc_create(cmd_t *);
117 static void parser_thread_create(cmd_t *);
118 static void parser_flowop_create(cmd_t *);
119 static void parser_fileset_create(cmd_t *);
120
121 /* set commands */
122 static void parser_set_integer(cmd_t *cmd);
123 static void parser_set_var(cmd_t *cmd);
124 static void parser_set_var_op_int(cmd_t *cmd);
125 static void parser_set_int_op_var(cmd_t *cmd);
126 static void parser_set_var_op_var(cmd_t *cmd);
127
128 /* Shutdown Commands */
129 static void parser_proc_shutdown(cmd_t *);
130 static void parser_filebench_shutdown(cmd_t *cmd);
131
132 /* Other Commands */
133 static void parser_echo(cmd_t *cmd);
134 static void parser_foreach_integer(cmd_t *cmd);
135 static void parser_foreach_string(cmd_t *cmd);
136 static void parser_fscheck(cmd_t *cmd);
137 static void parser_fsflush(cmd_t *cmd);
138 static void parser_log(cmd_t *cmd);
139 static void parser_statscmd(cmd_t *cmd);
140 static void parser_statsdump(cmd_t *cmd);
141 static void parser_statsxmldump(cmd_t *cmd);
142 static void parser_statsmultidump(cmd_t *cmd);
143 static void parser_usage(cmd_t *cmd);
144 static void parser_vars(cmd_t *cmd);
145 static void parser_printvars(cmd_t *cmd);
146 static void parser_system(cmd_t *cmd);
147 static void parser_statssnap(cmd_t *cmd);
148 static void parser_directory(cmd_t *cmd);
149 static void parser_eventgen(cmd_t *cmd);
150 static void parser_enable_mc(cmd_t *cmd);
151 static void parser_domultisync(cmd_t *cmd);
152 static void parser_run(cmd_t *cmd);
153 static void parser_run_variable(cmd_t *cmd);
154 static void parser_sleep(cmd_t *cmd);
155 static void parser_sleep_variable(cmd_t *cmd);
156 static void parser_warmup(cmd_t *cmd);
157 static void parser_warmup_variable(cmd_t *cmd);
158 static void parser_help(cmd_t *cmd);
159 static void arg_parse(const char *command);
160 static void parser_abort(int arg);
161 static void parser_version(cmd_t *cmd);
162
163 %}
164
165 %union {
166 int64_t ival;
167 uchar_t bval;
168 char * sval;
169 fs_u val;
170 avd_t avd;
171 cmd_t *cmd;
172 attr_t *attr;
173 list_t *list;
174 probtabent_t *rndtb;
175 }
176
177 %start commands
178
179 %token FSC_LIST FSC_DEFINE FSC_EXEC FSC_QUIT FSC_DEBUG FSC_CREATE
180 %token FSC_SLEEP FSC_STATS FSC_FOREACH FSC_SET FSC_SHUTDOWN FSC_LOG
181 %token FSC_SYSTEM FSC_FLOWOP FSC_EVENTGEN FSC_ECHO FSC_LOAD FSC_RUN
182 %token FSC_WARMUP FSC_NOUSESTATS FSC_FSCHECK FSC_FSFLUSH
183 %token FSC_USAGE FSC_HELP FSC_VARS FSC_VERSION FSC_ENABLE FSC_DOMULTISYNC
184 %token FSV_STRING FSV_VAL_INT FSV_VAL_BOOLEAN FSV_VARIABLE FSV_WHITESTRING
185 %token FSV_RANDUNI FSV_RANDTAB FSV_RANDVAR FSV_URAND FSV_RAND48
186 %token FST_INT FST_BOOLEAN
187 %token FSE_FILE FSE_PROC FSE_THREAD FSE_CLEAR FSE_ALL FSE_SNAP FSE_DUMP
188 %token FSE_DIRECTORY FSE_COMMAND FSE_FILESET FSE_XMLDUMP FSE_RAND FSE_MODE
189 %token FSE_MULTI FSE_MULTIDUMP
190 %token FSK_SEPLST FSK_OPENLST FSK_CLOSELST FSK_ASSIGN FSK_IN FSK_QUOTE
191 %token FSK_DIRSEPLST FSK_PLUS FSK_MINUS FSK_MULTIPLY FSK_DIVIDE
192 %token FSA_SIZE FSA_PREALLOC FSA_PARALLOC FSA_PATH FSA_REUSE
193 %token FSA_PROCESS FSA_MEMSIZE FSA_RATE FSA_CACHED FSA_READONLY FSA_TRUSTTREE
194 %token FSA_IOSIZE FSA_FILE FSA_WSS FSA_NAME FSA_RANDOM FSA_INSTANCES
195 %token FSA_DSYNC FSA_TARGET FSA_ITERS FSA_NICE FSA_VALUE FSA_BLOCKING
196 %token FSA_HIGHWATER FSA_DIRECTIO FSA_DIRWIDTH FSA_FD FSA_SRCFD FSA_ROTATEFD
197 %token FSA_NAMELENGTH FSA_FILESIZE FSA_ENTRIES FSA_FILESIZEGAMMA FSA_DIRDEPTHRV
198 %token FSA_DIRGAMMA FSA_USEISM FSA_TYPE FSA_RANDTABLE FSA_RANDSRC FSA_RANDROUND
199 %token FSA_LEAFDIRS FSA_INDEXED FSA_FSTYPE
200 %token FSA_RANDSEED FSA_RANDGAMMA FSA_RANDMEAN FSA_RANDMIN FSA_MASTER
201 %token FSA_CLIENT
202 %token FSS_TYPE FSS_SEED FSS_GAMMA FSS_MEAN FSS_MIN FSS_SRC FSS_ROUND
203 %token FSV_SET_LOCAL_VAR FSA_LVAR_ASSIGN
204 %token FSA_ALLDONE FSA_FIRSTDONE FSA_TIMEOUT
205
206 %type <ival> FSV_VAL_INT
207 %type <bval> FSV_VAL_BOOLEAN
208 %type <sval> FSV_STRING
209 %type <sval> FSV_WHITESTRING
210 %type <sval> FSV_VARIABLE
211 %type <sval> FSV_RANDVAR
212 %type <sval> FSK_ASSIGN
213 %type <sval> FSV_SET_LOCAL_VAR
214
215 %type <ival> FSC_LIST FSC_DEFINE FSC_SET FSC_LOAD FSC_RUN FSC_ENABLE
216 %type <ival> FSC_DOMULTISYNC
217 %type <ival> FSE_FILE FSE_PROC FSE_THREAD FSE_CLEAR FSC_HELP FSC_VERSION
218
219 %type <sval> name
220 %type <ival> entity
221 %type <val> value
222
223 %type <cmd> command inner_commands load_command run_command list_command
224 %type <cmd> proc_define_command files_define_command randvar_define_command
225 %type <cmd> fo_define_command debug_command create_command
226 %type <cmd> sleep_command stats_command set_command shutdown_command
227 %type <cmd> foreach_command log_command system_command flowop_command
228 %type <cmd> eventgen_command quit_command flowop_list thread_list
229 %type <cmd> thread echo_command usage_command help_command vars_command
230 %type <cmd> version_command enable_command multisync_command
231 %type <cmd> warmup_command fscheck_command fsflush_command
232 %type <cmd> set_integer_command set_other_command
233
234 %type <attr> files_attr_op files_attr_ops pt_attr_op pt_attr_ops
235 %type <attr> fo_attr_op fo_attr_ops ev_attr_op ev_attr_ops
236 %type <attr> randvar_attr_op randvar_attr_ops randvar_attr_typop
237 %type <attr> randvar_attr_srcop attr_value attr_list_value
238 %type <attr> comp_lvar_def comp_attr_op comp_attr_ops
239 %type <attr> enable_multi_ops enable_multi_op multisync_op
240 %type <attr> fscheck_attr_op
241 %type <list> integer_seplist string_seplist string_list var_string_list
242 %type <list> var_string whitevar_string whitevar_string_list
243 %type <ival> attrs_define_file attrs_define_thread attrs_flowop
244 %type <ival> attrs_define_fileset attrs_define_proc attrs_eventgen attrs_define_comp
245 %type <ival> files_attr_name pt_attr_name fo_attr_name ev_attr_name
246 %type <ival> randvar_attr_name FSA_TYPE randtype_name randvar_attr_param
247 %type <ival> randsrc_name FSA_RANDSRC randvar_attr_tsp em_attr_name
248 %type <ival> FSS_TYPE FSS_SEED FSS_GAMMA FSS_MEAN FSS_MIN FSS_SRC
249 %type <ival> fscheck_attr_name FSA_FSTYPE binary_op
250
251 %type <rndtb> probtabentry_list probtabentry
252 %type <avd> var_int_val
253 %%
254
255 commands: commands command
256 {
257 list_t *list = NULL;
258 list_t *list_end = NULL;
259
260 if ($2->cmd != NULL)
261 $2->cmd($2);
262
263 free($2);
264 }
265 | commands error
266 {
267 if (dofile)
268 YYABORT;
269 }
270 |;
271
272 inner_commands: command
273 {
274 filebench_log(LOG_DEBUG_IMPL, "inner_command %zx", $1);
275 $$ = $1;
276 }
277 | inner_commands command
278 {
279 cmd_t *list = NULL;
280 cmd_t *list_end = NULL;
281
282 /* Find end of list */
283 for (list = $1; list != NULL;
284 list = list->cmd_next)
285 list_end = list;
286
287 list_end->cmd_next = $2;
288
289 filebench_log(LOG_DEBUG_IMPL,
290 "inner_commands adding cmd %zx to list %zx", $2, $1);
291
292 $$ = $1;
293 };
294
295 command:
296 proc_define_command
297 | files_define_command
298 | randvar_define_command
299 | fo_define_command
300 | debug_command
301 | eventgen_command
302 | create_command
303 | echo_command
304 | usage_command
305 | vars_command
306 | foreach_command
307 | fscheck_command
308 | fsflush_command
309 | help_command
310 | list_command
311 | load_command
312 | log_command
313 | run_command
314 | set_command
315 | shutdown_command
316 | sleep_command
317 | warmup_command
318 | stats_command
319 | system_command
320 | version_command
321 | enable_command
322 | multisync_command
323 | quit_command;
324
325 foreach_command: FSC_FOREACH
326 {
327 if (($$ = alloc_cmd()) == NULL)
328 YYERROR;
329 filebench_log(LOG_DEBUG_IMPL, "foreach_command %zx", $$);
330 }
331 | foreach_command FSV_VARIABLE FSK_IN integer_seplist FSK_OPENLST inner_commands FSK_CLOSELST
332 {
333 cmd_t *cmd, *inner_cmd;
334 list_t *list;
335
336 $$ = $1;
337 $$->cmd_list = $6;
338 $$->cmd_tgt1 = $2;
339 $$->cmd_param_list = $4;
340 $$->cmd = parser_foreach_integer;
341
342 for (list = $$->cmd_param_list; list != NULL;
343 list = list->list_next) {
344 for (inner_cmd = $$->cmd_list;
345 inner_cmd != NULL;
346 inner_cmd = inner_cmd->cmd_next) {
347 filebench_log(LOG_DEBUG_IMPL,
348 "packing foreach: %zx %s=%llu, cmd %zx",
349 $$, $$->cmd_tgt1,
350 (u_longlong_t)avd_get_int(list->list_integer),
351 inner_cmd);
352 }
353 }
354 }| foreach_command FSV_VARIABLE FSK_IN string_seplist FSK_OPENLST inner_commands FSK_CLOSELST
355 {
356 cmd_t *cmd, *inner_cmd;
357 list_t *list;
358
359 $$ = $1;
360 $$->cmd_list = $6;
361 $$->cmd_tgt1 = $2;
362 $$->cmd_param_list = $4;
363 $$->cmd = parser_foreach_string;
364
365 for (list = $$->cmd_param_list; list != NULL;
366 list = list->list_next) {
367 for (inner_cmd = $$->cmd_list;
368 inner_cmd != NULL;
369 inner_cmd = inner_cmd->cmd_next) {
370 filebench_log(LOG_DEBUG_IMPL,
371 "packing foreach: %zx %s=%s, cmd %zx",
372 $$,
373 $$->cmd_tgt1,
374 *list->list_string, inner_cmd);
375 }
376 }
377 };
378
379 integer_seplist: FSV_VAL_INT
380 {
381 if (($$ = alloc_list()) == NULL)
382 YYERROR;
383
384 $$->list_integer = avd_int_alloc($1);
385 }
386 | integer_seplist FSK_SEPLST FSV_VAL_INT
387 {
388 list_t *list = NULL;
389 list_t *list_end = NULL;
390
391 if (($$ = alloc_list()) == NULL)
392 YYERROR;
393
394 $$->list_integer = avd_int_alloc($3);
395
396 /* Find end of list */
397 for (list = $1; list != NULL;
398 list = list->list_next)
399 list_end = list;
400 list_end->list_next = $$;
401 $$ = $1;
402 };
403
404 string_seplist: FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
405 {
406 if (($$ = alloc_list()) == NULL)
407 YYERROR;
408
409 $$->list_string = avd_str_alloc($2);
410 }
411 | string_seplist FSK_SEPLST FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
412 {
413 list_t *list = NULL;
414 list_t *list_end = NULL;
415
416 if (($$ = alloc_list()) == NULL)
417 YYERROR;
418
419 $$->list_string = avd_str_alloc($4);
420
421 /* Find end of list */
422 for (list = $1; list != NULL;
423 list = list->list_next)
424 list_end = list;
425 list_end->list_next = $$;
426 $$ = $1;
427 };
428
429 eventgen_command: FSC_EVENTGEN
430 {
431 if (($$ = alloc_cmd()) == NULL)
432 YYERROR;
433 $$->cmd = &parser_eventgen;
434 }
435 | eventgen_command ev_attr_ops
436 {
437 $1->cmd_attr_list = $2;
438 };
439
440 system_command: FSC_SYSTEM whitevar_string_list
441 {
442 if (($$ = alloc_cmd()) == NULL)
443 YYERROR;
444
445 $$->cmd_param_list = $2;
446 $$->cmd = parser_system;
447 };
448
449 echo_command: FSC_ECHO whitevar_string_list
450 {
451 if (($$ = alloc_cmd()) == NULL)
452 YYERROR;
453
454 $$->cmd_param_list = $2;
455 $$->cmd = parser_echo;
456 };
457
458 version_command: FSC_VERSION
459 {
460 if (($$ = alloc_cmd()) == NULL)
461 YYERROR;
462 $$->cmd = parser_version;
463 };
464
465 usage_command: FSC_USAGE whitevar_string_list
466 {
467 if (($$ = alloc_cmd()) == NULL)
468 YYERROR;
469
470 $$->cmd_param_list = $2;
471 $$->cmd = parser_usage;
472 };
473
474 vars_command: FSC_VARS
475 {
476 if (($$ = alloc_cmd()) == NULL)
477 YYERROR;
478
479 $$->cmd = parser_printvars;
480 };
481
482 enable_command: FSC_ENABLE FSE_MULTI
483 {
484 if (($$ = alloc_cmd()) == NULL)
485 YYERROR;
486
487 $$->cmd = parser_enable_mc;
488 }
489 | enable_command enable_multi_ops
490 {
491 $1->cmd_attr_list = $2;
492 };
493
494 multisync_command: FSC_DOMULTISYNC multisync_op
495 {
496 if (($$ = alloc_cmd()) == NULL)
497 YYERROR;
498
499 $$->cmd = parser_domultisync;
500 $$->cmd_attr_list = $2;
501 }
502
503 string_list: FSV_VARIABLE
504 {
505 if (($$ = alloc_list()) == NULL)
506 YYERROR;
507 $$->list_string = avd_str_alloc($1);
508 }
509 | string_list FSK_SEPLST FSV_VARIABLE
510 {
511 list_t *list = NULL;
512 list_t *list_end = NULL;
513
514 if (($$ = alloc_list()) == NULL)
515 YYERROR;
516
517 $$->list_string = avd_str_alloc($3);
518
519 /* Find end of list */
520 for (list = $1; list != NULL;
521 list = list->list_next)
522 list_end = list;
523 list_end->list_next = $$;
524 $$ = $1;
525 };
526
527 var_string: FSV_VARIABLE
528 {
529 if (($$ = alloc_list()) == NULL)
530 YYERROR;
531
532 $$->list_string = avd_str_alloc($1);
533 }
534 | FSV_STRING
535 {
536 if (($$ = alloc_list()) == NULL)
537 YYERROR;
538
539 $$->list_string = avd_str_alloc($1);
540 };
541
542 var_string_list: var_string
543 {
544 $$ = $1;
545 }| var_string FSV_STRING
546 {
547 list_t *list = NULL;
548 list_t *list_end = NULL;
549
550 /* Add string */
551 if (($$ = alloc_list()) == NULL)
552 YYERROR;
553
554 $$->list_string = avd_str_alloc($2);
555
556 /* Find end of list */
557 for (list = $1; list != NULL;
558 list = list->list_next)
559 list_end = list;
560 list_end->list_next = $$;
561 $$ = $1;
562
563 }| var_string FSV_VARIABLE
564 {
565 list_t *list = NULL;
566 list_t *list_end = NULL;
567
568 /* Add variable */
569 if (($$ = alloc_list()) == NULL)
570 YYERROR;
571
572 $$->list_string = avd_str_alloc($2);
573
574 /* Find end of list */
575 for (list = $1; list != NULL;
576 list = list->list_next)
577 list_end = list;
578 list_end->list_next = $$;
579 $$ = $1;
580 } |var_string_list FSV_STRING
581 {
582 list_t *list = NULL;
583 list_t *list_end = NULL;
584
585 /* Add string */
586 if (($$ = alloc_list()) == NULL)
587 YYERROR;
588
589 $$->list_string = avd_str_alloc($2);
590
591 /* Find end of list */
592 for (list = $1; list != NULL;
593 list = list->list_next)
594 list_end = list;
595 list_end->list_next = $$;
596 $$ = $1;
597
598 }| var_string_list FSV_VARIABLE
599 {
600 list_t *list = NULL;
601 list_t *list_end = NULL;
602
603 /* Add variable */
604 if (($$ = alloc_list()) == NULL)
605 YYERROR;
606
607 $$->list_string = avd_str_alloc($2);
608
609 /* Find end of list */
610 for (list = $1; list != NULL;
611 list = list->list_next)
612 list_end = list;
613 list_end->list_next = $$;
614 $$ = $1;
615 };
616
617 whitevar_string: FSK_QUOTE FSV_VARIABLE
618 {
619 if (($$ = alloc_list()) == NULL)
620 YYERROR;
621
622 $$->list_string = avd_str_alloc($2);
623 }
624 | FSK_QUOTE FSV_WHITESTRING
625 {
626 if (($$ = alloc_list()) == NULL)
627 YYERROR;
628
629 $$->list_string = avd_str_alloc($2);
630 };
631
632 whitevar_string_list: whitevar_string FSV_WHITESTRING
633 {
634 list_t *list = NULL;
635 list_t *list_end = NULL;
636
637 /* Add string */
638 if (($$ = alloc_list()) == NULL)
639 YYERROR;
640
641 $$->list_string = avd_str_alloc($2);
642
643 /* Find end of list */
644 for (list = $1; list != NULL;
645 list = list->list_next)
646 list_end = list;
647 list_end->list_next = $$;
648 $$ = $1;
649
650 }| whitevar_string FSV_VARIABLE
651 {
652 list_t *list = NULL;
653 list_t *list_end = NULL;
654
655 /* Add variable */
656 if (($$ = alloc_list()) == NULL)
657 YYERROR;
658
659 $$->list_string = avd_str_alloc($2);
660
661 /* Find end of list */
662 for (list = $1; list != NULL;
663 list = list->list_next)
664 list_end = list;
665 list_end->list_next = $$;
666 $$ = $1;
667 }| whitevar_string FSV_RANDVAR randvar_attr_tsp
668 {
669 list_t *list = NULL;
670 list_t *list_end = NULL;
671
672 /* Add variable */
673 if (($$ = alloc_list()) == NULL)
674 YYERROR;
675
676 $$->list_string = avd_str_alloc($2);
677 $$->list_integer = avd_int_alloc($3);
678
679 /* Find end of list */
680 for (list = $1; list != NULL;
681 list = list->list_next)
682 list_end = list;
683 list_end->list_next = $$;
684 $$ = $1;
685 }| whitevar_string_list FSV_WHITESTRING
686 {
687 list_t *list = NULL;
688 list_t *list_end = NULL;
689
690 /* Add string */
691 if (($$ = alloc_list()) == NULL)
692 YYERROR;
693
694 $$->list_string = avd_str_alloc($2);
695
696 /* Find end of list */
697 for (list = $1; list != NULL;
698 list = list->list_next)
699 list_end = list;
700 list_end->list_next = $$;
701 $$ = $1;
702
703 }| whitevar_string_list FSV_VARIABLE
704 {
705 list_t *list = NULL;
706 list_t *list_end = NULL;
707
708 /* Add variable */
709 if (($$ = alloc_list()) == NULL)
710 YYERROR;
711
712 $$->list_string = avd_str_alloc($2);
713
714 /* Find end of list */
715 for (list = $1; list != NULL;
716 list = list->list_next)
717 list_end = list;
718 list_end->list_next = $$;
719 $$ = $1;
720 }| whitevar_string_list FSV_RANDVAR randvar_attr_tsp
721 {
722 list_t *list = NULL;
723 list_t *list_end = NULL;
724
725 /* Add variable */
726 if (($$ = alloc_list()) == NULL)
727 YYERROR;
728
729 $$->list_string = avd_str_alloc($2);
730 $$->list_integer = avd_int_alloc($3);
731
732 /* Find end of list */
733 for (list = $1; list != NULL;
734 list = list->list_next)
735 list_end = list;
736 list_end->list_next = $$;
737 $$ = $1;
738 }| whitevar_string_list FSK_QUOTE
739 {
740 $$ = $1;
741 }| whitevar_string FSK_QUOTE
742 {
743 $$ = $1;
744 };
745
746 list_command: FSC_LIST
747 {
748 if (($$ = alloc_cmd()) == NULL)
749 YYERROR;
750 $$->cmd = &parser_list;
751 }
752 | list_command FSC_FLOWOP
753 {
754 $1->cmd = &parser_flowop_list;
755 };
756
757 fscheck_command: FSC_FSCHECK fscheck_attr_op
758 {
759 if (($$ = alloc_cmd()) == NULL)
760 YYERROR;
761 $$->cmd = &parser_fscheck;
762
763 $$->cmd_attr_list = $2;
764 }
765 | fscheck_command fscheck_attr_op
766 {
767 $1->cmd_attr_list->attr_next = $2;
768 };
769
770 fsflush_command: FSC_FSFLUSH fscheck_attr_op
771 {
772 if (($$ = alloc_cmd()) == NULL)
773 YYERROR;
774 $$->cmd = &parser_fsflush;
775
776 $$->cmd_attr_list = $2;
777 };
778
779 log_command: FSC_LOG whitevar_string_list
780 {
781 if (($$ = alloc_cmd()) == NULL)
782 YYERROR;
783 $$->cmd = &parser_log;
784 $$->cmd_param_list = $2;
785 };
786
787 debug_command: FSC_DEBUG FSV_VAL_INT
788 {
789 if (($$ = alloc_cmd()) == NULL)
790 YYERROR;
791 $$->cmd = NULL;
792 filebench_shm->shm_debug_level = $2;
793 if (filebench_shm->shm_debug_level > 9)
794 yydebug = 1;
795 };
796
797 set_command:
798 set_integer_command
799 | set_other_command;
800
801 set_integer_command: FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VAL_INT
802 {
803 if (($$ = alloc_cmd()) == NULL)
804 YYERROR;
805 $$->cmd_tgt1 = $2;
806 $$->cmd_qty = $4;
807 if (parentscript) {
808 parser_vars($$);
809 }
810 $$->cmd = parser_set_integer;
811 }| FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VARIABLE
812 {
813 if (($$ = alloc_cmd()) == NULL)
814 YYERROR;
815 var_assign_var($2, $4);
816 $$->cmd_tgt1 = $2;
817 $$->cmd_tgt2 = $4;
818 if (parentscript) {
819 parser_vars($$);
820 }
821 $$->cmd = parser_set_var;
822 }
823 | set_integer_command binary_op FSV_VAL_INT
824 {
825 if ($1->cmd == parser_set_integer) {
826 switch ($2) {
827 case FSK_PLUS:
828 var_assign_integer($1->cmd_tgt1, $1->cmd_qty + $3);
829 break;
830 case FSK_MINUS:
831 var_assign_integer($1->cmd_tgt1, $1->cmd_qty - $3);
832 break;
833 case FSK_MULTIPLY:
834 var_assign_integer($1->cmd_tgt1, $1->cmd_qty * $3);
835 break;
836 case FSK_DIVIDE:
837 var_assign_integer($1->cmd_tgt1, $1->cmd_qty / $3);
838 break;
839 }
840 $$->cmd = NULL;
841 } else {
842 $1->cmd_qty = $3;
843 $1->cmd_subtype = $2;
844 $1->cmd = parser_set_var_op_int;
845 }
846 }
847 | set_integer_command binary_op FSV_VARIABLE
848 {
849 $1->cmd_tgt3 = $3;
850 $1->cmd_subtype = $2;
851 if ($1->cmd == parser_set_integer) {
852 $$->cmd = parser_set_int_op_var;
853 } else {
854 $1->cmd = parser_set_var_op_var;
855 }
856 };
857
858 set_other_command: FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VAL_BOOLEAN
859 {
860 if (($$ = alloc_cmd()) == NULL)
861 YYERROR;
862 var_assign_boolean($2, $4);
863 if (parentscript) {
864 $$->cmd_tgt1 = $2;
865 parser_vars($$);
866 }
867 $$->cmd = NULL;
868 }
869 | FSC_SET FSV_VARIABLE FSK_ASSIGN FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
870 {
871 if (($$ = alloc_cmd()) == NULL)
872 YYERROR;
873 var_assign_string($2, $5);
874 if (parentscript) {
875 $$->cmd_tgt1 = $2;
876 parser_vars($$);
877 }
878 $$->cmd = NULL;
879 }| FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_STRING
880 {
881 if (($$ = alloc_cmd()) == NULL)
882 YYERROR;
883 var_assign_string($2, $4);
884 if (parentscript) {
885 $$->cmd_tgt1 = $2;
886 parser_vars($$);
887 }
888 $$->cmd = NULL;
889 } | FSC_SET FSE_MODE FSC_QUIT FSA_TIMEOUT
890 {
891 filebench_shm->shm_rmode = FILEBENCH_MODE_TIMEOUT;
892 if (($$ = alloc_cmd()) == NULL)
893 YYERROR;
894 $$->cmd = NULL;
895 } | FSC_SET FSE_MODE FSC_QUIT FSA_ALLDONE
896 {
897 filebench_shm->shm_rmode = FILEBENCH_MODE_QALLDONE;
898 if (($$ = alloc_cmd()) == NULL)
899 YYERROR;
900 $$->cmd = NULL;
901 } | FSC_SET FSE_MODE FSC_QUIT FSA_FIRSTDONE
902 {
903 filebench_shm->shm_rmode = FILEBENCH_MODE_Q1STDONE;
904 if (($$ = alloc_cmd()) == NULL)
905 YYERROR;
906 $$->cmd = NULL;
907 } | FSC_SET FSE_MODE FSC_NOUSESTATS
908 {
909 filebench_shm->shm_mmode |= FILEBENCH_MODE_NOUSAGE;
910 filebench_log(LOG_INFO, "disabling CPU usage statistics");
911 if (($$ = alloc_cmd()) == NULL)
912 YYERROR;
913 $$->cmd = NULL;
914 } | FSC_SET FSV_RANDVAR FSS_TYPE FSK_ASSIGN randvar_attr_typop
915 {
916 if (($$ = alloc_cmd()) == NULL)
917 YYERROR;
918 $$->cmd = &parser_randvar_set;
919 $$->cmd_tgt1 = $2;
920 $$->cmd_qty = FSS_TYPE;
921 $$->cmd_attr_list = $5;
922
923 } | FSC_SET FSV_RANDVAR FSS_SRC FSK_ASSIGN randvar_attr_srcop
924 {
925 if (($$ = alloc_cmd()) == NULL)
926 YYERROR;
927 $$->cmd = &parser_randvar_set;
928 $$->cmd_tgt1 = $2;
929 $$->cmd_qty = FSS_SRC;
930 $$->cmd_attr_list = $5;
931
932 } | FSC_SET FSV_RANDVAR randvar_attr_param FSK_ASSIGN attr_value
933 {
934 if (($$ = alloc_cmd()) == NULL)
935 YYERROR;
936 $$->cmd = &parser_randvar_set;
937 $$->cmd_tgt1 = $2;
938 $$->cmd_qty = $3;
939 $$->cmd_attr_list = $5;
940
941 };
942
943 stats_command: FSC_STATS FSE_SNAP
944 {
945 if (($$ = alloc_cmd()) == NULL)
946 YYERROR;
947 $$->cmd = (void (*)(struct cmd *))&parser_statssnap;
948 break;
949
950 }
951 | FSC_STATS FSE_CLEAR
952 {
953 if (($$ = alloc_cmd()) == NULL)
954 YYERROR;
955 $$->cmd = (void (*)(struct cmd *))&stats_clear;
956
957 }
958 | FSC_STATS FSE_DIRECTORY var_string_list
959 {
960 if (($$ = alloc_cmd()) == NULL)
961 YYERROR;
962 $$->cmd_param_list = $3;
963 $$->cmd = (void (*)(struct cmd *))&parser_directory;
964
965 }
966 | FSC_STATS FSE_COMMAND whitevar_string_list
967 {
968 if (($$ = alloc_cmd()) == NULL)
969 YYERROR;
970
971 $$->cmd_param_list = $3;
972 $$->cmd = parser_statscmd;
973
974 }| FSC_STATS FSE_DUMP whitevar_string_list
975 {
976 if (($$ = alloc_cmd()) == NULL)
977 YYERROR;
978
979 $$->cmd_param_list = $3;
980 $$->cmd = parser_statsdump;
981 }| FSC_STATS FSE_XMLDUMP whitevar_string_list
982 {
983 if (($$ = alloc_cmd()) == NULL)
984 YYERROR;
985
986 $$->cmd_param_list = $3;
987 $$->cmd = parser_statsxmldump;
988 }| FSC_STATS FSE_MULTIDUMP whitevar_string_list
989 {
990 if (($$ = alloc_cmd()) == NULL)
991 YYERROR;
992
993 $$->cmd_param_list = $3;
994 $$->cmd = parser_statsmultidump;
995 };
996
997 quit_command: FSC_QUIT
998 {
999 if (($$ = alloc_cmd()) == NULL)
1000 YYERROR;
1001 $$->cmd = parser_filebench_shutdown;
1002 };
1003
1004 flowop_list: flowop_command
1005 {
1006 $$ = $1;
1007 }| flowop_list flowop_command
1008 {
1009 cmd_t *list = NULL;
1010 cmd_t *list_end = NULL;
1011
1012 /* Find end of list */
1013 for (list = $1; list != NULL;
1014 list = list->cmd_next)
1015 list_end = list;
1016
1017 list_end->cmd_next = $2;
1018
1019 filebench_log(LOG_DEBUG_IMPL,
1020 "flowop_list adding cmd %zx to list %zx", $2, $1);
1021
1022 $$ = $1;
1023 };
1024
1025 thread: FSE_THREAD pt_attr_ops FSK_OPENLST flowop_list FSK_CLOSELST
1026 {
1027 /*
1028 * Allocate a cmd node per thread, with a
1029 * list of flowops attached to the cmd_list
1030 */
1031 if (($$ = alloc_cmd()) == NULL)
1032 YYERROR;
1033 $$->cmd_list = $4;
1034 $$->cmd_attr_list = $2;
1035 };
1036
1037 thread_list: thread
1038 {
1039 $$ = $1;
1040 }| thread_list thread
1041 {
1042 cmd_t *list = NULL;
1043 cmd_t *list_end = NULL;
1044
1045 /* Find end of list */
1046 for (list = $1; list != NULL;
1047 list = list->cmd_next)
1048 list_end = list;
1049
1050 list_end->cmd_next = $2;
1051
1052 filebench_log(LOG_DEBUG_IMPL,
1053 "thread_list adding cmd %zx to list %zx", $2, $1);
1054
1055 $$ = $1;
1056 };
1057
1058 proc_define_command: FSC_DEFINE FSE_PROC pt_attr_ops FSK_OPENLST thread_list FSK_CLOSELST
1059 {
1060 if (($$ = alloc_cmd()) == NULL)
1061 YYERROR;
1062 $$->cmd = &parser_proc_define;
1063 $$->cmd_list = $5;
1064 $$->cmd_attr_list = $3;
1065
1066 }
1067 | proc_define_command pt_attr_ops
1068 {
1069 $1->cmd_attr_list = $2;
1070 };
1071
1072 files_define_command: FSC_DEFINE FSE_FILE
1073 {
1074 if (($$ = alloc_cmd()) == NULL)
1075 YYERROR;
1076 $$->cmd = &parser_file_define;
1077 }| FSC_DEFINE FSE_FILESET
1078 {
1079 if (($$ = alloc_cmd()) == NULL)
1080 YYERROR;
1081 $$->cmd = &parser_fileset_define;
1082 }
1083 | files_define_command files_attr_ops
1084 {
1085 $1->cmd_attr_list = $2;
1086 };
1087
1088 randvar_define_command: FSC_DEFINE FSE_RAND randvar_attr_ops
1089 {
1090 if (($$ = alloc_cmd()) == NULL)
1091 YYERROR;
1092 $$->cmd = &parser_randvar_define;
1093 $$->cmd_attr_list = $3;
1094 };
1095
1096 fo_define_command: FSC_DEFINE FSC_FLOWOP comp_attr_ops FSK_OPENLST flowop_list FSK_CLOSELST
1097 {
1098 if (($$ = alloc_cmd()) == NULL)
1099 YYERROR;
1100 $$->cmd = &parser_composite_flowop_define;
1101 $$->cmd_list = $5;
1102 $$->cmd_attr_list = $3;
1103 }
1104 | fo_define_command comp_attr_ops
1105 {
1106 $1->cmd_attr_list = $2;
1107 };
1108
1109 create_command: FSC_CREATE entity
1110 {
1111 if (($$ = alloc_cmd()) == NULL)
1112 YYERROR;
1113 switch ($2) {
1114 case FSE_PROC:
1115 $$->cmd = &parser_proc_create;
1116 break;
1117 case FSE_FILESET:
1118 case FSE_FILE:
1119 $$->cmd = &parser_fileset_create;
1120 break;
1121 default:
1122 filebench_log(LOG_ERROR, "unknown entity", $2);
1123 YYERROR;
1124 }
1125
1126 };
1127
1128 shutdown_command: FSC_SHUTDOWN entity
1129 {
1130 if (($$ = alloc_cmd()) == NULL)
1131 YYERROR;
1132 switch ($2) {
1133 case FSE_PROC:
1134 $$->cmd = &parser_proc_shutdown;
1135 break;
1136 case FSE_FILE:
1137 case FSE_FILESET:
1138 $$->cmd = &parser_fileset_shutdown;
1139 break;
1140 default:
1141 filebench_log(LOG_ERROR, "unknown entity", $2);
1142 YYERROR;
1143 }
1144
1145 };
1146
1147 warmup_command: FSC_WARMUP FSV_VAL_INT
1148 {
1149 if (($$ = alloc_cmd()) == NULL)
1150 YYERROR;
1151 $$->cmd = parser_warmup;
1152 $$->cmd_qty = $2;
1153 }
1154 | FSC_WARMUP FSV_VARIABLE
1155 {
1156 fbint_t *integer;
1157
1158 if (($$ = alloc_cmd()) == NULL)
1159 YYERROR;
1160 $$->cmd = parser_warmup_variable;
1161 $$->cmd_tgt1 = fb_stralloc($2);
1162 };
1163
1164 sleep_command: FSC_SLEEP FSV_VAL_INT
1165 {
1166 if (($$ = alloc_cmd()) == NULL)
1167 YYERROR;
1168 $$->cmd = parser_sleep;
1169 $$->cmd_qty = $2;
1170 }
1171 | FSC_SLEEP FSV_VARIABLE
1172 {
1173 fbint_t *integer;
1174
1175 if (($$ = alloc_cmd()) == NULL)
1176 YYERROR;
1177 $$->cmd = parser_sleep_variable;
1178 $$->cmd_tgt1 = fb_stralloc($2);
1179 };
1180
1181 run_command: FSC_RUN FSV_VAL_INT
1182 {
1183 if (($$ = alloc_cmd()) == NULL)
1184 YYERROR;
1185 $$->cmd = parser_run;
1186 $$->cmd_qty = $2;
1187 }
1188 | FSC_RUN FSV_VARIABLE
1189 {
1190 fbint_t *integer;
1191
1192 if (($$ = alloc_cmd()) == NULL)
1193 YYERROR;
1194 $$->cmd = parser_run_variable;
1195 $$->cmd_tgt1 = fb_stralloc($2);
1196 }
1197 | FSC_RUN
1198 {
1199 fbint_t *integer;
1200
1201 if (($$ = alloc_cmd()) == NULL)
1202 YYERROR;
1203 $$->cmd = parser_run;
1204 $$->cmd_qty = 60UL;
1205 };
1206
1207 help_command: FSC_HELP
1208 {
1209 if (($$ = alloc_cmd()) == NULL)
1210 YYERROR;
1211 $$->cmd = parser_help;
1212 };
1213
1214 flowop_command: FSC_FLOWOP name
1215 {
1216 if (($$ = alloc_cmd()) == NULL)
1217 YYERROR;
1218 $$->cmd_name = fb_stralloc($2);
1219 }
1220 | flowop_command fo_attr_ops
1221 {
1222 $1->cmd_attr_list = $2;
1223 };
1224
1225 load_command: FSC_LOAD FSV_STRING
1226 {
1227 FILE *newfile;
1228 char loadfile[128];
1229
1230 if (($$ = alloc_cmd()) == NULL)
1231 YYERROR;
1232
1233 (void) strcpy(loadfile, $2);
1234 (void) strcat(loadfile, ".f");
1235
1236 if ((newfile = fopen(loadfile, "r")) == NULL) {
1237 (void) strcpy(loadfile, fbbasepath);
1238 (void) strcat(loadfile, "/workloads/");
1239 (void) strcat(loadfile, $2);
1240 (void) strcat(loadfile, ".f");
1241 if ((newfile = fopen(loadfile, "r")) == NULL) {
1242 filebench_log(LOG_ERROR, "Cannot open %s", loadfile);
1243 YYERROR;
1244 }
1245 }
1246
1247 parentscript = yyin;
1248 yyin = newfile;
1249 yy_switchfileparent(yyin);
1250 };
1251
1252
1253 entity: FSE_PROC {$$ = FSE_PROC;}
1254 | FSE_THREAD {$$ = FSE_THREAD;}
1255 | FSE_FILESET {$$ = FSE_FILESET;}
1256 | FSE_FILE {$$ = FSE_FILE;};
1257
1258 value: FSV_VAL_INT { $$.i = $1;}
1259 | FSV_STRING { $$.s = $1;}
1260 | FSV_VAL_BOOLEAN { $$.b = $1;};
1261
1262 name: FSV_STRING;
1263
1264 /* attribute parsing for define file and define fileset */
1265 files_attr_ops: files_attr_op
1266 {
1267 $$ = $1;
1268 }
1269 | files_attr_ops FSK_SEPLST files_attr_op
1270 {
1271 attr_t *attr = NULL;
1272 attr_t *list_end = NULL;
1273
1274 for (attr = $1; attr != NULL;
1275 attr = attr->attr_next)
1276 list_end = attr; /* Find end of list */
1277
1278 list_end->attr_next = $3;
1279
1280 $$ = $1;
1281 };
1282
1283 files_attr_op: files_attr_name FSK_ASSIGN attr_list_value
1284 {
1285 $$ = $3;
1286 $$->attr_name = $1;
1287 }
1288 | files_attr_name
1289 {
1290 if (($$ = alloc_attr()) == NULL)
1291 YYERROR;
1292 $$->attr_name = $1;
1293 };
1294
1295 /* attribute parsing for random variables */
1296 randvar_attr_ops: randvar_attr_op
1297 {
1298 $$ = $1;
1299 }
1300 | randvar_attr_ops FSK_SEPLST randvar_attr_op
1301 {
1302 attr_t *attr = NULL;
1303 attr_t *list_end = NULL;
1304
1305 for (attr = $1; attr != NULL;
1306 attr = attr->attr_next)
1307 list_end = attr; /* Find end of list */
1308
1309 list_end->attr_next = $3;
1310
1311 $$ = $1;
1312 }
1313 | randvar_attr_ops FSK_SEPLST FSA_RANDTABLE FSK_ASSIGN FSK_OPENLST probtabentry_list FSK_CLOSELST
1314 {
1315 attr_t *attr = NULL;
1316 attr_t *list_end = NULL;
1317
1318 for (attr = $1; attr != NULL;
1319 attr = attr->attr_next)
1320 list_end = attr; /* Find end of list */
1321
1322
1323 if ((attr = alloc_attr()) == NULL)
1324 YYERROR;
1325
1326 attr->attr_name = FSA_RANDTABLE;
1327 attr->attr_obj = (void *)$6;
1328 list_end->attr_next = attr;
1329 $$ = $1;
1330 };
1331
1332 randvar_attr_op: randvar_attr_name FSK_ASSIGN attr_list_value
1333 {
1334 $$ = $3;
1335 $$->attr_name = $1;
1336 }
1337 | randvar_attr_name
1338 {
1339 if (($$ = alloc_attr()) == NULL)
1340 YYERROR;
1341 $$->attr_name = $1;
1342 }
1343 | FSA_TYPE FSK_ASSIGN randvar_attr_typop
1344 {
1345 $$ = $3;
1346 $$->attr_name = FSA_TYPE;
1347 }
1348 | FSA_RANDSRC FSK_ASSIGN randvar_attr_srcop
1349 {
1350 $$ = $3;
1351 $$->attr_name = FSA_RANDSRC;
1352 };
1353
1354 probtabentry: FSK_OPENLST var_int_val FSK_SEPLST var_int_val FSK_SEPLST var_int_val FSK_CLOSELST
1355 {
1356 if (($$ = alloc_probtabent()) == NULL)
1357 YYERROR;
1358 $$->pte_percent = $2;
1359 $$->pte_segmin = $4;
1360 $$->pte_segmax = $6;
1361 };
1362
1363 /* attribute parsing for prob density function table */
1364 probtabentry_list: probtabentry
1365 {
1366 $$ = $1;
1367 }
1368 | probtabentry_list FSK_SEPLST probtabentry
1369 {
1370 probtabent_t *pte = NULL;
1371 probtabent_t *ptelist_end = NULL;
1372
1373 for (pte = $1; pte != NULL;
1374 pte = pte->pte_next)
1375 ptelist_end = pte; /* Find end of prob table entry list */
1376
1377 ptelist_end->pte_next = $3;
1378
1379 $$ = $1;
1380 };
1381
1382 /* attribute parsing for define thread and process */
1383 pt_attr_ops: pt_attr_op
1384 {
1385 $$ = $1;
1386 }
1387 | pt_attr_ops FSK_SEPLST pt_attr_op
1388 {
1389 attr_t *attr = NULL;
1390 attr_t *list_end = NULL;
1391
1392 for (attr = $1; attr != NULL;
1393 attr = attr->attr_next)
1394 list_end = attr; /* Find end of list */
1395
1396 list_end->attr_next = $3;
1397
1398 $$ = $1;
1399 };
1400
1401 pt_attr_op: pt_attr_name FSK_ASSIGN attr_value
1402 {
1403 $$ = $3;
1404 $$->attr_name = $1;
1405 }
1406 | pt_attr_name
1407 {
1408 if (($$ = alloc_attr()) == NULL)
1409 YYERROR;
1410 $$->attr_name = $1;
1411 };
1412
1413 /* attribute parsing for flowops */
1414 fo_attr_ops: fo_attr_op
1415 {
1416 $$ = $1;
1417 }
1418 | fo_attr_ops FSK_SEPLST fo_attr_op
1419 {
1420 attr_t *attr = NULL;
1421 attr_t *list_end = NULL;
1422
1423 for (attr = $1; attr != NULL;
1424 attr = attr->attr_next)
1425 list_end = attr; /* Find end of list */
1426
1427 list_end->attr_next = $3;
1428
1429 $$ = $1;
1430 }
1431 | fo_attr_ops FSK_SEPLST comp_lvar_def
1432 {
1433 attr_t *attr = NULL;
1434 attr_t *list_end = NULL;
1435
1436 for (attr = $1; attr != NULL;
1437 attr = attr->attr_next)
1438 list_end = attr; /* Find end of list */
1439
1440 list_end->attr_next = $3;
1441
1442 $$ = $1;
1443 };
1444
1445 fo_attr_op: fo_attr_name FSK_ASSIGN attr_value
1446 {
1447 $$ = $3;
1448 $$->attr_name = $1;
1449 }
1450 | fo_attr_name
1451 {
1452 if (($$ = alloc_attr()) == NULL)
1453 YYERROR;
1454 $$->attr_name = $1;
1455 };
1456
1457 /* attribute parsing for Event Generator */
1458 ev_attr_ops: ev_attr_op
1459 {
1460 $$ = $1;
1461 }
1462 | ev_attr_ops FSK_SEPLST ev_attr_op
1463 {
1464 attr_t *attr = NULL;
1465 attr_t *list_end = NULL;
1466
1467 for (attr = $1; attr != NULL;
1468 attr = attr->attr_next)
1469 list_end = attr; /* Find end of list */
1470
1471 list_end->attr_next = $3;
1472
1473 $$ = $1;
1474 };
1475
1476 ev_attr_op: ev_attr_name FSK_ASSIGN attr_value
1477 {
1478 $$ = $3;
1479 $$->attr_name = $1;
1480 }
1481 | ev_attr_name
1482 {
1483 if (($$ = alloc_attr()) == NULL)
1484 YYERROR;
1485 $$->attr_name = $1;
1486 };
1487
1488 /* attribute parsing for enable multiple client command */
1489 enable_multi_ops: enable_multi_op
1490 {
1491 $$ = $1;
1492 }
1493 | enable_multi_ops FSK_SEPLST enable_multi_op
1494 {
1495 attr_t *attr = NULL;
1496 attr_t *list_end = NULL;
1497
1498 for (attr = $1; attr != NULL;
1499 attr = attr->attr_next)
1500 list_end = attr; /* Find end of list */
1501
1502 list_end->attr_next = $3;
1503
1504 $$ = $1;
1505 };
1506
1507 enable_multi_op: em_attr_name FSK_ASSIGN attr_value
1508 {
1509 $$ = $3;
1510 $$->attr_name = $1;
1511 };
1512
1513 multisync_op: FSA_VALUE FSK_ASSIGN attr_value
1514 {
1515 $$ = $3;
1516 $$->attr_name = FSA_VALUE;
1517 };
1518
1519 fscheck_attr_op: fscheck_attr_name FSK_ASSIGN FSV_STRING
1520 {
1521 if (($$ = alloc_attr()) == NULL)
1522 YYERROR;
1523 $$->attr_avd = avd_str_alloc($3);
1524 $$->attr_name = $1;
1525 };
1526
1527 binary_op:
1528 FSK_PLUS {$$ = FSK_PLUS;}
1529 | FSK_MINUS {$$ = FSK_MINUS;}
1530 | FSK_MULTIPLY {$$ = FSK_MULTIPLY;}
1531 | FSK_DIVIDE {$$ = FSK_DIVIDE;};
1532
1533 files_attr_name: attrs_define_file
1534 |attrs_define_fileset;
1535
1536 pt_attr_name: attrs_define_thread
1537 |attrs_define_proc;
1538
1539 fo_attr_name: attrs_flowop;
1540
1541 ev_attr_name: attrs_eventgen;
1542
1543 attrs_define_proc:
1544 FSA_NICE { $$ = FSA_NICE;}
1545 | FSA_NAME { $$ = FSA_NAME;}
1546 | FSA_INSTANCES { $$ = FSA_INSTANCES;};
1547
1548 attrs_define_file:
1549 FSA_SIZE { $$ = FSA_SIZE;}
1550 | FSA_NAME { $$ = FSA_NAME;}
1551 | FSA_PATH { $$ = FSA_PATH;}
1552 | FSA_READONLY { $$ = FSA_READONLY;}
1553 | FSA_TRUSTTREE { $$ = FSA_TRUSTTREE;}
1554 | FSA_REUSE { $$ = FSA_REUSE;}
1555 | FSA_PREALLOC { $$ = FSA_PREALLOC;}
1556 | FSA_PARALLOC { $$ = FSA_PARALLOC;};
1557
1558 attrs_define_fileset:
1559 FSA_SIZE { $$ = FSA_SIZE;}
1560 | FSA_NAME { $$ = FSA_NAME;}
1561 | FSA_PATH { $$ = FSA_PATH;}
1562 | FSA_DIRWIDTH { $$ = FSA_DIRWIDTH;}
1563 | FSA_DIRDEPTHRV { $$ = FSA_DIRDEPTHRV;}
1564 | FSA_PREALLOC { $$ = FSA_PREALLOC;}
1565 | FSA_PARALLOC { $$ = FSA_PARALLOC;}
1566 | FSA_REUSE { $$ = FSA_REUSE;}
1567 | FSA_READONLY { $$ = FSA_READONLY;}
1568 | FSA_TRUSTTREE { $$ = FSA_TRUSTTREE;}
1569 | FSA_FILESIZEGAMMA { $$ = FSA_FILESIZEGAMMA;}
1570 | FSA_DIRGAMMA { $$ = FSA_DIRGAMMA;}
1571 | FSA_CACHED { $$ = FSA_CACHED;}
1572 | FSA_ENTRIES { $$ = FSA_ENTRIES;}
1573 | FSA_LEAFDIRS { $$ = FSA_LEAFDIRS;};
1574
1575 randvar_attr_name:
1576 FSA_NAME { $$ = FSA_NAME;}
1577 | FSA_RANDSEED { $$ = FSA_RANDSEED;}
1578 | FSA_RANDGAMMA { $$ = FSA_RANDGAMMA;}
1579 | FSA_RANDMEAN { $$ = FSA_RANDMEAN;}
1580 | FSA_RANDMIN { $$ = FSA_RANDMIN;}
1581 | FSA_RANDROUND { $$ = FSA_RANDROUND;};
1582
1583 randvar_attr_tsp:
1584 FSS_TYPE { $$ = FSS_TYPE;}
1585 | FSS_SRC { $$ = FSS_SRC;}
1586 | FSS_SEED { $$ = FSS_SEED;}
1587 | FSS_GAMMA { $$ = FSS_GAMMA;}
1588 | FSS_MEAN { $$ = FSS_MEAN;}
1589 | FSS_MIN { $$ = FSS_MIN;}
1590 | FSS_ROUND { $$ = FSS_ROUND;};
1591
1592
1593 randvar_attr_param:
1594 FSS_SEED { $$ = FSS_SEED;}
1595 | FSS_GAMMA { $$ = FSS_GAMMA;}
1596 | FSS_MEAN { $$ = FSS_MEAN;}
1597 | FSS_MIN { $$ = FSS_MIN;}
1598 | FSS_ROUND { $$ = FSS_ROUND;};
1599
1600 randvar_attr_typop: randtype_name
1601 {
1602 if (($$ = alloc_attr()) == NULL)
1603 YYERROR;
1604 $$->attr_avd = avd_int_alloc($1);
1605 };
1606
1607 randtype_name:
1608 FSV_RANDUNI { $$ = FSV_RANDUNI;}
1609 | FSV_RANDTAB { $$ = FSV_RANDTAB;}
1610 | FSA_RANDGAMMA { $$ = FSA_RANDGAMMA;};
1611
1612 randvar_attr_srcop: randsrc_name
1613 {
1614 if (($$ = alloc_attr()) == NULL)
1615 YYERROR;
1616 $$->attr_avd = avd_int_alloc($1);
1617 };
1618
1619 randsrc_name:
1620 FSV_URAND { $$ = FSV_URAND;}
1621 | FSV_RAND48 { $$ = FSV_RAND48;};
1622
1623 attrs_define_thread:
1624 FSA_PROCESS { $$ = FSA_PROCESS;}
1625 | FSA_NAME { $$ = FSA_NAME;}
1626 | FSA_MEMSIZE { $$ = FSA_MEMSIZE;}
1627 | FSA_USEISM { $$ = FSA_USEISM;}
1628 | FSA_INSTANCES { $$ = FSA_INSTANCES;};
1629
1630 attrs_flowop:
1631 FSA_WSS { $$ = FSA_WSS;}
1632 | FSA_FILE { $$ = FSA_FILE;}
1633 | FSA_NAME { $$ = FSA_NAME;}
1634 | FSA_RANDOM { $$ = FSA_RANDOM;}
1635 | FSA_FD { $$ = FSA_FD;}
1636 | FSA_SRCFD { $$ = FSA_SRCFD;}
1637 | FSA_ROTATEFD { $$ = FSA_ROTATEFD;}
1638 | FSA_DSYNC { $$ = FSA_DSYNC;}
1639 | FSA_DIRECTIO { $$ = FSA_DIRECTIO;}
1640 | FSA_INDEXED { $$ = FSA_INDEXED;}
1641 | FSA_TARGET { $$ = FSA_TARGET;}
1642 | FSA_ITERS { $$ = FSA_ITERS;}
1643 | FSA_VALUE { $$ = FSA_VALUE;}
1644 | FSA_BLOCKING { $$ = FSA_BLOCKING;}
1645 | FSA_HIGHWATER { $$ = FSA_HIGHWATER;}
1646 | FSA_IOSIZE { $$ = FSA_IOSIZE;};
1647
1648 attrs_eventgen:
1649 FSA_RATE { $$ = FSA_RATE;};
1650
1651 em_attr_name:
1652 FSA_MASTER { $$ = FSA_MASTER;}
1653 | FSA_CLIENT { $$ = FSA_CLIENT;};
1654
1655 fscheck_attr_name:
1656 FSA_PATH { $$ = FSA_PATH;}
1657 | FSA_FSTYPE { $$ = FSA_FSTYPE;};
1658
1659 comp_attr_ops: comp_attr_op
1660 {
1661 $$ = $1;
1662 }
1663 | comp_attr_ops FSK_SEPLST comp_attr_op
1664 {
1665 attr_t *attr = NULL;
1666 attr_t *list_end = NULL;
1667
1668 for (attr = $1; attr != NULL;
1669 attr = attr->attr_next)
1670 list_end = attr; /* Find end of list */
1671
1672 list_end->attr_next = $3;
1673
1674 $$ = $1;
1675 }
1676 | comp_attr_ops FSK_SEPLST comp_lvar_def
1677 {
1678 attr_t *attr = NULL;
1679 attr_t *list_end = NULL;
1680
1681 for (attr = $1; attr != NULL;
1682 attr = attr->attr_next)
1683 list_end = attr; /* Find end of list */
1684
1685 list_end->attr_next = $3;
1686
1687 $$ = $1;
1688 };
1689
1690 comp_attr_op: attrs_define_comp FSK_ASSIGN attr_value
1691 {
1692 $$ = $3;
1693 $$->attr_name = $1;
1694 };
1695
1696 comp_lvar_def: FSV_VARIABLE FSK_ASSIGN FSV_VAL_BOOLEAN
1697 {
1698 if (($$ = alloc_lvar_attr(var_lvar_assign_boolean($1, $3))) == NULL)
1699 YYERROR;
1700 }
1701 | FSV_VARIABLE FSK_ASSIGN FSV_VAL_INT
1702 {
1703 if (($$ = alloc_lvar_attr(var_lvar_assign_integer($1, $3))) == NULL)
1704 YYERROR;
1705 }
1706 | FSV_VARIABLE FSK_ASSIGN FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
1707 {
1708 if (($$ = alloc_lvar_attr(var_lvar_assign_string($1, $4))) == NULL)
1709 YYERROR;
1710 }
1711 | FSV_VARIABLE FSK_ASSIGN FSV_STRING
1712 {
1713 if (($$ = alloc_lvar_attr(var_lvar_assign_string($1, $3))) == NULL)
1714 YYERROR;
1715 }
1716 | FSV_VARIABLE FSK_ASSIGN FSV_VARIABLE
1717 {
1718 if (($$ = alloc_lvar_attr(var_lvar_assign_var($1, $3))) == NULL)
1719 YYERROR;
1720 }
1721 | FSV_VARIABLE
1722 {
1723 if (($$ = alloc_lvar_attr(var_lvar_alloc_local($1))) == NULL)
1724 YYERROR;
1725 };
1726
1727
1728 attrs_define_comp:
1729 FSA_NAME { $$ = FSA_NAME;}
1730 | FSA_ITERS { $$ = FSA_ITERS;};
1731
1732 attr_value: FSV_STRING
1733 {
1734 if (($$ = alloc_attr()) == NULL)
1735 YYERROR;
1736 $$->attr_avd = avd_str_alloc($1);
1737 } | FSV_VAL_INT {
1738 if (($$ = alloc_attr()) == NULL)
1739 YYERROR;
1740 $$->attr_avd = avd_int_alloc($1);
1741 } | FSV_VAL_BOOLEAN {
1742 if (($$ = alloc_attr()) == NULL)
1743 YYERROR;
1744 $$->attr_avd = avd_bool_alloc($1);
1745 } | FSV_VARIABLE {
1746 if (($$ = alloc_attr()) == NULL)
1747 YYERROR;
1748 $$->attr_avd = var_ref_attr($1);
1749 };
1750
1751 attr_list_value: var_string_list {
1752 if (($$ = alloc_attr()) == NULL)
1753 YYERROR;
1754 $$->attr_param_list = $1;
1755 } | FSV_STRING {
1756 if (($$ = alloc_attr()) == NULL)
1757 YYERROR;
1758 $$->attr_avd = avd_str_alloc($1);
1759 } | FSV_VAL_INT {
1760 if (($$ = alloc_attr()) == NULL)
1761 YYERROR;
1762 $$->attr_avd = avd_int_alloc($1);
1763 } | FSV_VAL_BOOLEAN {
1764 if (($$ = alloc_attr()) == NULL)
1765 YYERROR;
1766 $$->attr_avd = avd_bool_alloc($1);
1767 } | FSV_VARIABLE {
1768 if (($$ = alloc_attr()) == NULL)
1769 YYERROR;
1770 $$->attr_avd = var_ref_attr($1);
1771 };
1772
1773 var_int_val: FSV_VAL_INT
1774 {
1775 $$ = avd_int_alloc($1);
1776 } | FSV_VARIABLE
1777 {
1778 $$ = var_ref_attr($1);
1779 };
1780
1781 %%
1782
1783 /*
1784 * The following 'c' routines implement the various commands defined in the
1785 * above yacc parser code. The yacc portion checks the syntax of the commands
1786 * found in a workload file, or typed on interactive command lines, parsing
1787 * the commands' parameters into lists. The lists are then passed in a cmd_t
1788 * struct for each command to its related routine in the following section
1789 * for actual execution. This section also includes a few utility routines
1790 * and the main entry point for the program.
1791 */
1792
1793 /*
1794 * Entry point for filebench. Processes command line arguements. The -f
1795 * option will read in a workload file (the full name and extension must
1796 * must be given). The -a, -s, -m and -i options are used by worker process
1797 * to receive their name, the base address of shared memory, its path, and
1798 * the process' instance number, respectively. This information is supplied
1799 * by the master process when it execs worker processes under the process
1800 * model of execution. If the worker process arguments are passed then main
1801 * will call the procflow_exec routine which creates worker threadflows and
1802 * flowops and executes the procflow's portion of the workload model until
1803 * completion. If worker process arguments are not passed to the process,
1804 * then it becomes the master process for a filebench run. It initializes
1805 * the various filebench components and either executes the supplied workload
1806 * file, or enters interactive mode.
1807 */
1808
1809 int
1810 main(int argc, char *argv[])
1811 {
1812 int opt;
1813 int docmd = FS_FALSE;
1814 int instance;
1815 char procname[128];
1816 caddr_t shmaddr;
1817 char dir[MAXPATHLEN];
1818 #ifdef HAVE_SETRLIMIT
1819 struct rlimit rlp;
1820 #endif
1821 #ifdef HAVE_LIBTECLA
1822 char *line;
1823 #else
1824 char line[1024];
1825 #endif
1826 char shmpathtmp[1024];
1827
1828 #ifdef HAVE_SETRLIMIT
1829 /* Set resource limits */
1830 (void) getrlimit(RLIMIT_NOFILE, &rlp);
1831 rlp.rlim_cur = rlp.rlim_max;
1832 setrlimit(RLIMIT_NOFILE, &rlp);
1833 #endif
1834
1835 yydebug = 0;
1836 execname = argv[0];
1837 *procname = 0;
1838 cwd = getcwd(dir, MAXPATHLEN);
1839
1840 while ((opt = getopt(argc, argv, cmd_options)) != (int)EOF) {
1841
1842 switch (opt) {
1843 case 'h':
1844 usage(2);
1845 break;
1846
1847 case 'p':
1848 noproc = 1;
1849 break;
1850
1851 case 'f':
1852 if (optarg == NULL)
1853 usage(1);
1854 if ((yyin = fopen(optarg, "r")) == NULL) {
1855 (void) fprintf(stderr,
1856 "Cannot open file %s", optarg);
1857 exit(1);
1858 }
1859 dofile = FS_TRUE;
1860 fscriptname = optarg;
1861
1862 break;
1863
1864 case 'a':
1865 if (optarg == NULL)
1866 usage(1);
1867 sscanf(optarg, "%s", &procname[0]);
1868 break;
1869
1870 case 's':
1871 if (optarg == NULL)
1872 usage(1);
1873 #if defined(_LP64) || (__WORDSIZE == 64)
1874 sscanf(optarg, "%llx", &shmaddr);
1875 #else
1876 sscanf(optarg, "%x", &shmaddr);
1877 #endif
1878 break;
1879
1880 case 'm':
1881 if (optarg == NULL)
1882 usage(1);
1883 sscanf(optarg, "%s", shmpathtmp);
1884 shmpath = shmpathtmp;
1885 break;
1886
1887 case 'i':
1888 if (optarg == NULL)
1889 usage(1);
1890 sscanf(optarg, "%d", &instance);
1891 break;
1892
1893 case '?':
1894 default:
1895 usage(1);
1896 break;
1897 }
1898 }
1899
1900 #ifdef USE_PROCESS_MODEL
1901 if (!(*procname))
1902 #endif
1903 printf("FileBench Version %s\n", FILEBENCH_VERSION);
1904 filebench_init();
1905
1906 /* get process pid for use with message logging */
1907 my_pid = getpid();
1908
1909 #ifdef USE_PROCESS_MODEL
1910 if (*procname) {
1911 /* A child FileBench instance */
1912 if (ipc_attach(shmaddr) < 0) {
1913 filebench_log(LOG_ERROR, "Cannot attach shm for %s",
1914 procname);
1915 exit(1);
1916 }
1917
1918 /* get correct function pointer for each child process */
1919 filebench_plugin_funcvecinit();
1920
1921 if (procflow_exec(procname, instance) < 0) {
1922 filebench_log(LOG_ERROR, "Cannot startup process %s",
1923 procname);
1924 exit(1);
1925 }
1926
1927 exit(0);
1928 }
1929 #endif
1930
1931 /* master (or only) process */
1932 ipc_init();
1933
1934 if (fscriptname)
1935 (void) strcpy(filebench_shm->shm_fscriptname, fscriptname);
1936
1937 filebench_plugin_funcvecinit();
1938 flowop_init();
1939 stats_init();
1940 eventgen_init();
1941
1942 signal(SIGINT, parser_abort);
1943
1944 if (dofile)
1945 yyparse();
1946 else {
1947 #ifdef HAVE_LIBTECLA
1948 if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) {
1949 filebench_log(LOG_ERROR,
1950 "Failed to create GetLine object");
1951 filebench_shutdown(1);
1952 }
1953
1954 if (gl_customize_completion(gl, NULL, command_complete)) {
1955 filebench_log(LOG_ERROR,
1956 "Failed to register auto-completion function");
1957 filebench_shutdown(1);
1958 }
1959
1960 while (line = gl_get_line(gl, FILEBENCH_PROMPT, NULL, -1)) {
1961 arg_parse(line);
1962 yyparse();
1963 }
1964
1965 del_GetLine(gl);
1966 #else
1967 while (!feof(stdin)) {
1968 printf(FILEBENCH_PROMPT);
1969 fflush(stdout);
1970 if (fgets(line, sizeof (line), stdin) == NULL) {
1971 if (errno == EINTR)
1972 continue;
1973 else
1974 break;
1975 }
1976 arg_parse(line);
1977 yyparse();
1978 }
1979 printf("\n");
1980 #endif /* HAVE_LIBTECLA */
1981 }
1982
1983 parser_filebench_shutdown((cmd_t *)0);
1984
1985 return (0);
1986 }
1987
1988 /*
1989 * arg_parse() puts the parser into command parsing mode. Create a tmpfile
1990 * and instruct the parser to read instructions from this location by setting
1991 * yyin to the value returned by tmpfile. Write the command into the file.
1992 * Then seek back to to the start of the file so that the parser can read
1993 * the instructions.
1994 */
1995 static void
arg_parse(const char * command)1996 arg_parse(const char *command)
1997 {
1998 if ((yyin = tmpfile()) == NULL) {
1999 filebench_log(LOG_FATAL,
2000 "Exiting: Cannot create tmpfile: %s", strerror(errno));
2001 exit(1);
2002 }
2003
2004 if (fwrite(command, strlen(command), 1, yyin) != 1)
2005 filebench_log(LOG_FATAL,
2006 "Cannot write tmpfile: %s", strerror(errno));
2007
2008 if (fseek(yyin, 0, SEEK_SET) != 0)
2009 filebench_log(LOG_FATAL,
2010 "Cannot seek tmpfile: %s", strerror(errno));
2011 }
2012
2013 /*
2014 * Converts a list of var_strings or ordinary strings to a single ordinary
2015 * string. It returns a pointer to the string (in malloc'd memory) if found,
2016 * or NULL otherwise.
2017 */
2018 char *
parser_list2string(list_t * list)2019 parser_list2string(list_t *list)
2020 {
2021 list_t *l;
2022 char *string;
2023 char *tmp;
2024 fbint_t *integer;
2025 if ((string = malloc(MAXPATHLEN)) == NULL) {
2026 filebench_log(LOG_ERROR, "Failed to allocate memory");
2027 return (NULL);
2028 }
2029
2030 *string = 0;
2031
2032 /* printf("parser_list2string: called\n"); */
2033 /* Format args */
2034 for (l = list; l != NULL; l = l->list_next) {
2035 char *lstr = avd_get_str(l->list_string);
2036
2037 filebench_log(LOG_DEBUG_SCRIPT,
2038 "converting string '%s'", lstr);
2039
2040 /* see if it is a random variable */
2041 if (l->list_integer) {
2042 fbint_t param_name;
2043
2044 tmp = NULL;
2045 param_name = avd_get_int(l->list_integer);
2046 switch (param_name) {
2047 case FSS_TYPE:
2048 tmp = var_randvar_to_string(lstr,
2049 RAND_PARAM_TYPE);
2050 break;
2051
2052 case FSS_SRC:
2053 tmp = var_randvar_to_string(lstr,
2054 RAND_PARAM_SRC);
2055 break;
2056
2057 case FSS_SEED:
2058 tmp = var_randvar_to_string(lstr,
2059 RAND_PARAM_SEED);
2060 break;
2061
2062 case FSS_MIN:
2063 tmp = var_randvar_to_string(lstr,
2064 RAND_PARAM_MIN);
2065 break;
2066
2067 case FSS_MEAN:
2068 tmp = var_randvar_to_string(lstr,
2069 RAND_PARAM_MEAN);
2070 break;
2071
2072 case FSS_GAMMA:
2073 tmp = var_randvar_to_string(lstr,
2074 RAND_PARAM_GAMMA);
2075 break;
2076
2077 case FSS_ROUND:
2078 tmp = var_randvar_to_string(lstr,
2079 RAND_PARAM_ROUND);
2080 break;
2081 }
2082
2083 if (tmp) {
2084 (void) strcat(string, tmp);
2085 free(tmp);
2086 } else {
2087 (void) strcat(string, lstr);
2088 }
2089 } else {
2090 /* perhaps a normal variable? */
2091 if ((tmp = var_to_string(lstr)) != NULL) {
2092 (void) strcat(string, tmp);
2093 free(tmp);
2094 } else {
2095 (void) strcat(string, lstr);
2096 }
2097 }
2098 }
2099 return (string);
2100 }
2101
2102 /*
2103 * If the list just contains a single string starting with '$', then find
2104 * or create the named var and return the var's var_string component.
2105 * Otherwise, convert the list to a string, and allocate a var_string
2106 * containing a copy of that string. On failure either returns NULL
2107 * or shuts down the run.
2108 */
2109 avd_t
parser_list2varstring(list_t * list)2110 parser_list2varstring(list_t *list)
2111 {
2112 char *lstr = avd_get_str(list->list_string);
2113
2114 /* printf("parser_list2varstring: Called\n"); */
2115 /* Special case - variable name */
2116 if ((list->list_next == NULL) && (*lstr == '$'))
2117 return (var_ref_attr(lstr));
2118
2119 return (avd_str_alloc(parser_list2string(list)));
2120 }
2121
2122 /*
2123 * Looks for the var named in list_string of the first element of the
2124 * supplied list. If found, returns the var_val portion of the var in
2125 * an attribute value descriptor. If the var is not found, cannot be
2126 * allocated, the supplied list is NULL, or the list_string filed is
2127 * empty, returns NULL.
2128 */
2129 avd_t
parser_list2avd(list_t * list)2130 parser_list2avd(list_t *list)
2131 {
2132 avd_t avd;
2133 char *lstr;
2134
2135 if (list && ((lstr = avd_get_str(list->list_string)) != NULL)) {
2136 avd = var_ref_attr(lstr);
2137 return (avd);
2138 }
2139
2140 return (NULL);
2141 }
2142
2143 /*
2144 * Sets the event generator rate from the attribute supplied with the
2145 * command. If the attribute doesn't exist the routine does nothing.
2146 */
2147 static void
parser_eventgen(cmd_t * cmd)2148 parser_eventgen(cmd_t *cmd)
2149 {
2150 attr_t *attr;
2151
2152 /* Get the rate from attribute */
2153 if (attr = get_attr_integer(cmd, FSA_RATE)) {
2154 if (attr->attr_avd) {
2155 eventgen_setrate(attr->attr_avd);
2156 }
2157 }
2158 }
2159
2160 /*
2161 * Assigns the designated integer variable successive values from the
2162 * supplied comma seperated integer list. After each successive integer
2163 * assignment, it executes the bracket enclosed list of commands. For
2164 * example, repeated runs of a workload with increasing io sizes can
2165 * be done using the following command line:
2166 * foreach $iosize in 2k, 4k, 8k {run 60}
2167 */
2168 static void
parser_foreach_integer(cmd_t * cmd)2169 parser_foreach_integer(cmd_t *cmd)
2170 {
2171 list_t *list = cmd->cmd_param_list;
2172 cmd_t *inner_cmd;
2173
2174 for (; list != NULL; list = list->list_next) {
2175 fbint_t list_int = avd_get_int(list->list_integer);
2176
2177 var_assign_integer(cmd->cmd_tgt1, list_int);
2178 filebench_log(LOG_VERBOSE, "Iterating %s=%llu",
2179 cmd->cmd_tgt1, (u_longlong_t)list_int);
2180 for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
2181 inner_cmd = inner_cmd->cmd_next) {
2182 inner_cmd->cmd(inner_cmd);
2183 }
2184 }
2185 }
2186
2187 /*
2188 * Similar to parser_foreach_integer(), except takes a list of strings after
2189 * the "in" token. For example, to run twice using a different directory,
2190 * perhaps using a different filesystem, the following command line
2191 * could be used:
2192 * foreach $dir in "/ufs_top/fbt", "/zfs_top/fbt" {run 60)
2193 */
2194 static void
parser_foreach_string(cmd_t * cmd)2195 parser_foreach_string(cmd_t *cmd)
2196 {
2197 list_t *list = cmd->cmd_param_list;
2198
2199 for (; list != NULL; list = list->list_next) {
2200 cmd_t *inner_cmd;
2201 char *lstr = avd_get_str(list->list_string);
2202 var_assign_string(cmd->cmd_tgt1, lstr);
2203 filebench_log(LOG_VERBOSE, "Iterating %s=%s",
2204 cmd->cmd_tgt1, lstr);
2205 for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
2206 inner_cmd = inner_cmd->cmd_next) {
2207 inner_cmd->cmd(inner_cmd);
2208 }
2209 }
2210 }
2211
2212 /*
2213 * Lists the fileset name, path name and average size for all defined
2214 * filesets.
2215 */
2216 static void
parser_list(cmd_t * cmd)2217 parser_list(cmd_t *cmd)
2218 {
2219 (void) fileset_iter(fileset_print);
2220 }
2221
2222 /*
2223 * Lists the flowop name and instance number for all flowops.
2224 */
2225 static void
parser_flowop_list(cmd_t * cmd)2226 parser_flowop_list(cmd_t *cmd)
2227 {
2228 flowop_printall();
2229 }
2230
2231 /*
2232 * Calls procflow_define() to allocate "instances" number of procflow(s)
2233 * (processes) with the supplied name. The default number of instances is
2234 * one. An optional priority level attribute can be supplied and is stored in
2235 * pf_nice. Finally the routine loops through the list of inner commands, if
2236 * any, which are defines for threadflows, and passes them one at a time to
2237 * parser_thread_define() to allocate threadflow entities for the process(es).
2238 */
2239 static void
parser_proc_define(cmd_t * cmd)2240 parser_proc_define(cmd_t *cmd)
2241 {
2242 procflow_t *procflow, template;
2243 char *name;
2244 attr_t *attr;
2245 avd_t var_instances;
2246 fbint_t instances;
2247 cmd_t *inner_cmd;
2248
2249 /* Get the name of the process */
2250 if (attr = get_attr(cmd, FSA_NAME)) {
2251 name = avd_get_str(attr->attr_avd);
2252 } else {
2253 filebench_log(LOG_ERROR,
2254 "define proc: proc specifies no name");
2255 filebench_shutdown(1);
2256 }
2257
2258 /* Get the memory size from attribute */
2259 if (attr = get_attr_integer(cmd, FSA_INSTANCES)) {
2260 if (AVD_IS_RANDOM(attr->attr_avd)) {
2261 filebench_log(LOG_ERROR,
2262 "proc_define: Instances attr cannot be random");
2263 filebench_shutdown(1);
2264 }
2265 var_instances = attr->attr_avd;
2266 instances = avd_get_int(var_instances);
2267 filebench_log(LOG_DEBUG_IMPL,
2268 "Setting instances = %llu", (u_longlong_t)instances);
2269 } else {
2270 filebench_log(LOG_DEBUG_IMPL,
2271 "Defaulting to instances = 1");
2272 var_instances = avd_int_alloc(1);
2273 instances = 1;
2274 }
2275
2276 if ((procflow = procflow_define(name, NULL, var_instances)) == NULL) {
2277 filebench_log(LOG_ERROR,
2278 "Failed to instantiate %d %s process(es)\n",
2279 instances, name);
2280 filebench_shutdown(1);
2281 }
2282
2283 /* Get the pri from attribute */
2284 if (attr = get_attr_integer(cmd, FSA_NICE)) {
2285 if (AVD_IS_RANDOM(attr->attr_avd)) {
2286 filebench_log(LOG_ERROR,
2287 "proc_define: priority cannot be random");
2288 filebench_shutdown(1);
2289 }
2290 filebench_log(LOG_DEBUG_IMPL, "Setting pri = %llu",
2291 (u_longlong_t)avd_get_int(attr->attr_avd));
2292 procflow->pf_nice = attr->attr_avd;
2293 } else
2294 procflow->pf_nice = avd_int_alloc(0);
2295
2296
2297 /* Create the list of threads for this process */
2298 for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
2299 inner_cmd = inner_cmd->cmd_next) {
2300 parser_thread_define(inner_cmd, procflow, instances);
2301 }
2302 }
2303
2304 /*
2305 * Calls threadflow_define() to allocate "instances" number of threadflow(s)
2306 * (threads) with the supplied name. The default number of instances is
2307 * one. Two other optional attributes may be supplied, one to set the memory
2308 * size, stored in tf_memsize, and to select the use of Interprocess Shared
2309 * Memory, which sets the THREADFLOW_USEISM flag in tf_attrs. Finally
2310 * the routine loops through the list of inner commands, if any, which are
2311 * defines for flowops, and passes them one at a time to
2312 * parser_flowop_define() to allocate flowop entities for the threadflows.
2313 */
2314 static void
parser_thread_define(cmd_t * cmd,procflow_t * procflow,int procinstances)2315 parser_thread_define(cmd_t *cmd, procflow_t *procflow, int procinstances)
2316 {
2317 threadflow_t *threadflow, template;
2318 attr_t *attr;
2319 avd_t instances;
2320 cmd_t *inner_cmd;
2321 char *name;
2322
2323 memset(&template, 0, sizeof (threadflow_t));
2324
2325 /* Get the name of the thread */
2326 if (attr = get_attr(cmd, FSA_NAME)) {
2327 name = avd_get_str(attr->attr_avd);
2328 } else {
2329 filebench_log(LOG_ERROR,
2330 "define thread: thread in process %s specifies no name",
2331 procflow->pf_name);
2332 filebench_shutdown(1);
2333 }
2334
2335 /* Get the number of instances from attribute */
2336 if (attr = get_attr_integer(cmd, FSA_INSTANCES)) {
2337 if (AVD_IS_RANDOM(attr->attr_avd)) {
2338 filebench_log(LOG_ERROR,
2339 "define thread: Instances attr cannot be random");
2340 filebench_shutdown(1);
2341 }
2342 filebench_log(LOG_DEBUG_IMPL,
2343 "define thread: Setting instances = %llu",
2344 (u_longlong_t)avd_get_int(attr->attr_avd));
2345 instances = attr->attr_avd;
2346 } else
2347 instances = avd_int_alloc(1);
2348
2349 /* Get the memory size from attribute */
2350 if (attr = get_attr_integer(cmd, FSA_MEMSIZE)) {
2351 if (AVD_IS_RANDOM(attr->attr_avd)) {
2352 filebench_log(LOG_ERROR,
2353 "define thread: Memory size cannot be random");
2354 filebench_shutdown(1);
2355 }
2356 filebench_log(LOG_DEBUG_IMPL,
2357 "define thread: Setting memsize = %llu",
2358 (u_longlong_t)avd_get_int(attr->attr_avd));
2359 template.tf_memsize = attr->attr_avd;
2360 } else
2361 template.tf_memsize = avd_int_alloc(0);
2362
2363 if ((threadflow = threadflow_define(procflow, name,
2364 &template, instances)) == NULL) {
2365 filebench_log(LOG_ERROR,
2366 "define thread: Failed to instantiate thread\n");
2367 filebench_shutdown(1);
2368 }
2369
2370 /* Use ISM Memory? */
2371 if (attr = get_attr(cmd, FSA_USEISM)) {
2372 threadflow->tf_attrs |= THREADFLOW_USEISM;
2373 }
2374
2375 /* Create the list of flowops */
2376 for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
2377 inner_cmd = inner_cmd->cmd_next) {
2378 parser_flowop_define(inner_cmd, threadflow,
2379 &threadflow->tf_thrd_fops, FLOW_MASTER);
2380 }
2381 }
2382
2383 /*
2384 * Fills in the attributes for a newly allocated flowop
2385 */
2386 static void
parser_flowop_get_attrs(cmd_t * cmd,flowop_t * flowop)2387 parser_flowop_get_attrs(cmd_t *cmd, flowop_t *flowop)
2388 {
2389 attr_t *attr;
2390
2391 /* Get the filename from attribute */
2392 if (attr = get_attr(cmd, FSA_FILE)) {
2393 flowop->fo_filename = attr->attr_avd;
2394 if (flowop->fo_filename == NULL) {
2395 filebench_log(LOG_ERROR,
2396 "define flowop: no filename specfied");
2397 filebench_shutdown(1);
2398 }
2399 } else {
2400 /* no filename attribute specified */
2401 flowop->fo_filename = NULL;
2402 }
2403
2404 /* Get the iosize of the op */
2405 if (attr = get_attr_integer(cmd, FSA_IOSIZE))
2406 flowop->fo_iosize = attr->attr_avd;
2407 else
2408 flowop->fo_iosize = avd_int_alloc(0);
2409
2410 /* Get the working set size of the op */
2411 if (attr = get_attr_integer(cmd, FSA_WSS))
2412 flowop->fo_wss = attr->attr_avd;
2413 else
2414 flowop->fo_wss = avd_int_alloc(0);
2415
2416 /* Random I/O? */
2417 if (attr = get_attr_bool(cmd, FSA_RANDOM))
2418 flowop->fo_random = attr->attr_avd;
2419 else
2420 flowop->fo_random = avd_bool_alloc(FALSE);
2421
2422 /* Sync I/O? */
2423 if (attr = get_attr_bool(cmd, FSA_DSYNC))
2424 flowop->fo_dsync = attr->attr_avd;
2425 else
2426 flowop->fo_dsync = avd_bool_alloc(FALSE);
2427
2428 /* Target, for wakeup etc */
2429 if (attr = get_attr(cmd, FSA_TARGET))
2430 (void) strcpy(flowop->fo_targetname,
2431 avd_get_str(attr->attr_avd));
2432
2433 /* Value */
2434 if (attr = get_attr_integer(cmd, FSA_VALUE))
2435 flowop->fo_value = attr->attr_avd;
2436 else
2437 flowop->fo_value = avd_int_alloc(0);
2438
2439 /* FD */
2440 if (attr = get_attr_integer(cmd, FSA_FD)) {
2441 flowop->fo_fdnumber = avd_get_int(attr->attr_avd);
2442 if (flowop->fo_filename != NULL)
2443 filebench_log(LOG_DEBUG_SCRIPT, "It is not "
2444 "advisable to supply both an fd number "
2445 "and a fileset name in most cases");
2446 }
2447
2448 /* Rotatefd? */
2449 if (attr = get_attr_bool(cmd, FSA_ROTATEFD))
2450 flowop->fo_rotatefd = attr->attr_avd;
2451 else
2452 flowop->fo_rotatefd = avd_bool_alloc(FALSE);
2453
2454 /* SRC FD, for copies etc... */
2455 if (attr = get_attr_integer(cmd, FSA_SRCFD))
2456 flowop->fo_srcfdnumber = avd_get_int(attr->attr_avd);
2457
2458 /* Blocking operation? */
2459 if (attr = get_attr_bool(cmd, FSA_BLOCKING))
2460 flowop->fo_blocking = attr->attr_avd;
2461 else
2462 flowop->fo_blocking = avd_bool_alloc(FALSE);
2463
2464 /* Direct I/O Operation */
2465 if (attr = get_attr_bool(cmd, FSA_DIRECTIO))
2466 flowop->fo_directio = attr->attr_avd;
2467 else
2468 flowop->fo_directio = avd_bool_alloc(FALSE);
2469
2470 /* Highwater mark */
2471 if (attr = get_attr_integer(cmd, FSA_HIGHWATER)) {
2472 flowop->fo_highwater = attr->attr_avd;
2473 if (AVD_IS_RANDOM(attr->attr_avd)) {
2474 filebench_log(LOG_ERROR,
2475 "define flowop: Highwater attr cannot be random");
2476 filebench_shutdown(1);
2477 }
2478 } else {
2479 flowop->fo_highwater = avd_int_alloc(1);
2480 }
2481
2482 /* find file or leaf directory by index number */
2483 if (attr = get_attr_integer(cmd, FSA_INDEXED))
2484 flowop->fo_fileindex = attr->attr_avd;
2485 else
2486 flowop->fo_fileindex = NULL;
2487 }
2488
2489 /*
2490 * defines the FLOW_MASTER flowops within a FLOW_MASTER instance of
2491 * a composit flowop. Default attributes from the FLOW_INNER_DEF instances
2492 * of the composit flowop's inner flowops are used if set. Otherwise
2493 * default attributes from the FLOW_MASTER instance of the composit flowop
2494 * are used, which may include defaults from the original FLOW_DEFINITION
2495 * of the composit flowop.
2496 */
2497 static void
parser_inner_flowop_define(threadflow_t * thread,flowop_t * comp0_flow,flowop_t * comp_mstr_flow)2498 parser_inner_flowop_define(threadflow_t *thread, flowop_t *comp0_flow,
2499 flowop_t *comp_mstr_flow)
2500 {
2501 flowop_t *inner_flowtype, *inner_flowop;
2502
2503 /* follow flowop list, creating composit names */
2504 inner_flowtype = comp0_flow->fo_comp_fops;
2505 comp_mstr_flow->fo_comp_fops = NULL;
2506
2507 while (inner_flowtype) {
2508 char fullname[MAXPATHLEN];
2509
2510 /* create composite_name.name for new flowop */
2511 snprintf(fullname, MAXPATHLEN, "%s.%s",
2512 comp_mstr_flow->fo_name, inner_flowtype->fo_name);
2513
2514 if ((inner_flowop = flowop_define(thread, fullname,
2515 inner_flowtype, &comp_mstr_flow->fo_comp_fops,
2516 FLOW_MASTER, 0)) == NULL) {
2517 filebench_log(LOG_ERROR,
2518 "define flowop: Failed to instantiate flowop %s\n",
2519 fullname);
2520 filebench_shutdown(1);
2521 }
2522
2523 /* if applicable, update filename attribute */
2524 if (inner_flowop->fo_filename) {
2525 char *name;
2526
2527 /* fix up avd_t */
2528 avd_update(&inner_flowop->fo_filename,
2529 comp_mstr_flow->fo_lvar_list);
2530
2531 /* see if ready to get the file or fileset */
2532 name = avd_get_str(inner_flowop->fo_filename);
2533 if (name) {
2534
2535 inner_flowop->fo_fileset = fileset_find(name);
2536
2537 if (inner_flowop->fo_fileset == NULL) {
2538 filebench_log(LOG_ERROR,
2539 "inr flowop %s: file %s not found",
2540 inner_flowop->fo_name, name);
2541 filebench_shutdown(1);
2542 }
2543 }
2544 }
2545
2546 /* update attributes from local variables */
2547 avd_update(&inner_flowop->fo_iters,
2548 comp_mstr_flow->fo_lvar_list);
2549
2550 /* if the inner flowop is a composit flowop, recurse */
2551 if (inner_flowtype->fo_type == FLOW_TYPE_COMPOSITE) {
2552 var_t *newlvar, *proto_lvars, *lvar_ptr;
2553
2554 proto_lvars = inner_flowop->fo_lvar_list;
2555 inner_flowop->fo_lvar_list = 0;
2556
2557 for (lvar_ptr = inner_flowtype->fo_lvar_list; lvar_ptr;
2558 lvar_ptr = lvar_ptr->var_next) {
2559
2560 if ((newlvar = var_lvar_alloc_local(
2561 lvar_ptr->var_name)) != NULL) {
2562
2563 add_lvar_to_list(newlvar,
2564 &inner_flowop->fo_lvar_list);
2565
2566 var_update_comp_lvars(newlvar,
2567 proto_lvars,
2568 comp_mstr_flow->fo_lvar_list);
2569 }
2570 }
2571
2572 parser_inner_flowop_define(thread,
2573 inner_flowtype,
2574 inner_flowop);
2575
2576 inner_flowtype = inner_flowtype->fo_exec_next;
2577 continue;
2578 }
2579
2580 avd_update(&inner_flowop->fo_iosize,
2581 comp_mstr_flow->fo_lvar_list);
2582 avd_update(&inner_flowop->fo_wss,
2583 comp_mstr_flow->fo_lvar_list);
2584 avd_update(&inner_flowop->fo_iters,
2585 comp_mstr_flow->fo_lvar_list);
2586 avd_update(&inner_flowop->fo_value,
2587 comp_mstr_flow->fo_lvar_list);
2588 avd_update(&inner_flowop->fo_random,
2589 comp_mstr_flow->fo_lvar_list);
2590 avd_update(&inner_flowop->fo_dsync,
2591 comp_mstr_flow->fo_lvar_list);
2592 avd_update(&inner_flowop->fo_rotatefd,
2593 comp_mstr_flow->fo_lvar_list);
2594 avd_update(&inner_flowop->fo_blocking,
2595 comp_mstr_flow->fo_lvar_list);
2596 avd_update(&inner_flowop->fo_directio,
2597 comp_mstr_flow->fo_lvar_list);
2598 avd_update(&inner_flowop->fo_highwater,
2599 comp_mstr_flow->fo_lvar_list);
2600
2601 inner_flowtype = inner_flowtype->fo_exec_next;
2602 }
2603 }
2604
2605 /*
2606 * Calls flowop_define() to allocate a flowop with the supplied name.
2607 * The allocated flowop inherits attributes from a base flowop of the
2608 * same type. If the new flowop has a file or fileset attribute specified,
2609 * it must specify a defined fileobj or fileset or an error will be logged.
2610 * The new flowop may also have the following attributes set by
2611 * the program:
2612 * - file size (fo_iosize)
2613 * - working set size (fo_wss)
2614 * - do random io (fo_random)
2615 * - do synchronous io (fo_dsync)
2616 * - perform each operation multiple times before advancing (fo_iter)
2617 * - target name (fo_targetname)
2618 * - An integer value (fo_value)
2619 * - a file descriptor (fo_fd)
2620 * - specify to rotate file descriptors (fo_rotatefd)
2621 * - a source fd (fo_srcfdnumber)
2622 * - specify a blocking operation (fo_blocking)
2623 * - specify a highwater mark (fo_highwater)
2624 *
2625 * After all the supplied attributes are stored in their respective locations
2626 * in the flowop object, the flowop's init function is called. No errors are
2627 * returned, but the filebench run will be terminated if the flowtype is not
2628 * specified, a name for the new flowop is not supplied, the flowop_define
2629 * call fails, or a file or fileset name is supplied but the corresponding
2630 * fileobj or fileset cannot be located.
2631 */
2632 static void
parser_flowop_define(cmd_t * cmd,threadflow_t * thread,flowop_t ** flowoplist_hdp,int category)2633 parser_flowop_define(cmd_t *cmd, threadflow_t *thread,
2634 flowop_t **flowoplist_hdp, int category)
2635 {
2636 flowop_t *flowop, *flowop_type;
2637 char *type = (char *)cmd->cmd_name;
2638 char *name;
2639 attr_t *attr;
2640
2641 /* Get the inherited flowop */
2642 flowop_type = flowop_find(type);
2643 if (flowop_type == NULL) {
2644 filebench_log(LOG_ERROR,
2645 "define flowop: flowop type %s not found",
2646 type);
2647 filebench_shutdown(1);
2648 }
2649
2650 /* Get the name of the flowop */
2651 if (attr = get_attr(cmd, FSA_NAME)) {
2652 name = avd_get_str(attr->attr_avd);
2653 } else {
2654 filebench_log(LOG_ERROR,
2655 "define flowop: flowop %s specifies no name",
2656 flowop_type->fo_name);
2657 filebench_shutdown(1);
2658 }
2659
2660 if ((flowop = flowop_define(thread, name,
2661 flowop_type, flowoplist_hdp, category, 0)) == NULL) {
2662 filebench_log(LOG_ERROR,
2663 "define flowop: Failed to instantiate flowop %s\n",
2664 cmd->cmd_name);
2665 filebench_shutdown(1);
2666 }
2667
2668 /* Iterations */
2669 if (attr = get_attr_integer(cmd, FSA_ITERS))
2670 flowop->fo_iters = attr->attr_avd;
2671 else
2672 flowop->fo_iters = avd_int_alloc(1);
2673
2674
2675 /* if this is a use of a composit flowop, create inner FLOW MASTERS */
2676 if (flowop_type->fo_type == FLOW_TYPE_COMPOSITE) {
2677 get_attr_lvars(cmd, flowop);
2678 if (category == FLOW_MASTER)
2679 parser_inner_flowop_define(thread,
2680 flowop_type, flowop);
2681 }
2682 else {
2683 parser_flowop_get_attrs(cmd, flowop);
2684 }
2685 }
2686
2687 static void
parser_composite_flowop_define(cmd_t * cmd)2688 parser_composite_flowop_define(cmd_t *cmd)
2689 {
2690 flowop_t *flowop;
2691 cmd_t *inner_cmd;
2692 char *name;
2693 attr_t *attr;
2694
2695 /* Get the name of the flowop */
2696 if (attr = get_attr(cmd, FSA_NAME)) {
2697 name = avd_get_str(attr->attr_avd);
2698 } else {
2699 filebench_log(LOG_ERROR,
2700 "define flowop: Composit flowop specifies no name");
2701
2702 filebench_shutdown(1);
2703 }
2704
2705 if ((flowop = flowop_new_composite_define(name)) == NULL) {
2706 filebench_log(LOG_ERROR,
2707 "define flowop: Failed to instantiate flowop %s\n",
2708 cmd->cmd_name);
2709 filebench_shutdown(1);
2710 }
2711
2712 /* place any local var_t variables on the flowop's local list */
2713 get_attr_lvars(cmd, flowop);
2714
2715 /* Iterations */
2716 if (attr = get_attr_integer(cmd, FSA_ITERS))
2717 flowop->fo_iters = attr->attr_avd;
2718 else
2719 flowop->fo_iters = avd_int_alloc(1);
2720
2721 /* define inner flowops */
2722 for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
2723 inner_cmd = inner_cmd->cmd_next) {
2724 parser_flowop_define(inner_cmd, NULL,
2725 &flowop->fo_comp_fops, FLOW_INNER_DEF);
2726 }
2727 }
2728
2729
2730 /*
2731 * Calls fileset_define() to allocate a fileset with the supplied name and
2732 * initializes the fileset's pathname attribute, and optionally the
2733 * fileset_cached, fileset_reuse, fileset_prealloc and fileset_size attributes.
2734 *
2735 */
2736 static fileset_t *
parser_fileset_define_common(cmd_t * cmd)2737 parser_fileset_define_common(cmd_t *cmd)
2738 {
2739 fileset_t *fileset;
2740 avd_t name;
2741 attr_t *attr;
2742 avd_t pathname;
2743
2744 /*
2745 * Make sure all plugin flowops are initialized.
2746 * Defaults to local fs for now
2747 */
2748 flowop_plugin_flowinit();
2749
2750 /* Get the name of the file */
2751 if (attr = get_attr_fileset(cmd, FSA_NAME)) {
2752 name = attr->attr_avd;
2753 } else {
2754 filebench_log(LOG_ERROR,
2755 "define fileset: file or fileset specifies no name");
2756 return (NULL);
2757 }
2758
2759 if ((fileset = fileset_define(name)) == NULL) {
2760 filebench_log(LOG_ERROR,
2761 "define file: failed to instantiate file %s\n",
2762 avd_get_str(name));
2763 return (NULL);
2764 }
2765
2766 /* Get the pathname from attribute */
2767 if ((attr = get_attr(cmd, FSA_PATH)) == NULL) {
2768 filebench_log(LOG_ERROR, "define file: no pathname specified");
2769 return (NULL);
2770 }
2771
2772 /* Expand variables in pathname */
2773 if ((pathname = parser_list2varstring(attr->attr_param_list))
2774 == NULL) {
2775 filebench_log(LOG_ERROR, "Cannot interpret path");
2776 return (NULL);
2777 }
2778
2779 fileset->fs_path = pathname;
2780
2781 /* How much should we preallocate? */
2782 if ((attr = get_attr_integer(cmd, FSA_PREALLOC)) &&
2783 attr->attr_avd) {
2784 if (AVD_IS_RANDOM(attr->attr_avd)) {
2785 filebench_log(LOG_ERROR,
2786 "define fileset: Prealloc attr cannot be random");
2787 filebench_shutdown(1);
2788 }
2789 fileset->fs_preallocpercent = attr->attr_avd;
2790 } else if (attr && !attr->attr_avd) {
2791 fileset->fs_preallocpercent = avd_int_alloc(100);
2792 } else {
2793 fileset->fs_preallocpercent = avd_int_alloc(0);
2794 }
2795
2796 /* Should we preallocate? */
2797 if (attr = get_attr_bool(cmd, FSA_PREALLOC))
2798 fileset->fs_prealloc = attr->attr_avd;
2799 else
2800 fileset->fs_prealloc = avd_bool_alloc(FALSE);
2801
2802 /* Should we prealloc in parallel? */
2803 if (attr = get_attr_bool(cmd, FSA_PARALLOC))
2804 fileset->fs_paralloc = attr->attr_avd;
2805 else
2806 fileset->fs_paralloc = avd_bool_alloc(FALSE);
2807
2808 /* Should we allow writes to the file? */
2809 if (attr = get_attr_bool(cmd, FSA_READONLY))
2810 fileset->fs_readonly = attr->attr_avd;
2811 else
2812 fileset->fs_readonly = avd_bool_alloc(FALSE);
2813
2814 /* Should we reuse the existing file? */
2815 if (attr = get_attr_bool(cmd, FSA_REUSE))
2816 fileset->fs_reuse = attr->attr_avd;
2817 else
2818 fileset->fs_reuse = avd_bool_alloc(FALSE);
2819
2820 /* Should we check for files actual existance? */
2821 if (attr = get_attr_bool(cmd, FSA_TRUSTTREE))
2822 fileset->fs_trust_tree = attr->attr_avd;
2823 else
2824 fileset->fs_trust_tree = avd_bool_alloc(FALSE);
2825
2826 /* Should we leave in cache? */
2827 if (attr = get_attr_bool(cmd, FSA_CACHED))
2828 fileset->fs_cached = attr->attr_avd;
2829 else
2830 fileset->fs_cached = avd_bool_alloc(FALSE);
2831
2832 /* Get the mean or absolute size of the file */
2833 if (attr = get_attr_integer(cmd, FSA_SIZE))
2834 fileset->fs_size = attr->attr_avd;
2835 else
2836 fileset->fs_size = avd_int_alloc(0);
2837
2838 return (fileset);
2839 }
2840
2841 /*
2842 * Calls parser_fileset_define_common() to allocate a fileset with
2843 * one entry and optionally the fileset_prealloc. sets the fileset_entries,
2844 * fileset_dirwidth, fileset_dirgamma, and fileset_sizegamma attributes
2845 * to appropriate values for emulating the old "fileobj" entity
2846 */
2847 static void
parser_file_define(cmd_t * cmd)2848 parser_file_define(cmd_t *cmd)
2849 {
2850 fileset_t *fileset;
2851 attr_t *attr;
2852
2853 if ((fileset = parser_fileset_define_common(cmd)) == NULL) {
2854 filebench_log(LOG_ERROR,
2855 "define file: failed to instantiate file");
2856 filebench_shutdown(1);
2857 return;
2858 }
2859
2860 /* fileset is emulating a single file */
2861 fileset->fs_attrs = FILESET_IS_FILE;
2862
2863 /* Set the size of the fileset to 1 */
2864 fileset->fs_entries = avd_int_alloc(1);
2865
2866 /* Set the mean dir width to more than 1 */
2867 fileset->fs_dirwidth = avd_int_alloc(10);
2868
2869 /* Set the dir and size gammas to 0 */
2870 fileset->fs_dirgamma = avd_int_alloc(0);
2871 fileset->fs_sizegamma = avd_int_alloc(0);
2872 }
2873
2874 /*
2875 * Calls parser_fileset_define_common() to allocate a fileset with the
2876 * supplied name and initializes the fileset's fileset_preallocpercent,
2877 * fileset_prealloc, fileset_entries, fileset_dirwidth, fileset_dirgamma,
2878 * and fileset_sizegamma attributes.
2879 */
2880 static void
parser_fileset_define(cmd_t * cmd)2881 parser_fileset_define(cmd_t *cmd)
2882 {
2883 fileset_t *fileset;
2884 attr_t *attr;
2885
2886 if ((fileset = parser_fileset_define_common(cmd)) == NULL) {
2887 filebench_log(LOG_ERROR,
2888 "define fileset: failed to instantiate fileset");
2889 filebench_shutdown(1);
2890 return;
2891 }
2892 /* Get the number of files in the fileset */
2893 if (attr = get_attr_integer(cmd, FSA_ENTRIES)) {
2894 fileset->fs_entries = attr->attr_avd;
2895 } else {
2896 fileset->fs_entries = avd_int_alloc(0);
2897 }
2898
2899 /* Get the number of leafdirs in the fileset */
2900 if (attr = get_attr_integer(cmd, FSA_LEAFDIRS)) {
2901 fileset->fs_leafdirs = attr->attr_avd;
2902 } else {
2903 fileset->fs_leafdirs = avd_int_alloc(0);
2904 }
2905
2906 if ((avd_get_int(fileset->fs_entries) == 0) &&
2907 (avd_get_int(fileset->fs_leafdirs) == 0)) {
2908 filebench_log(LOG_ERROR, "Fileset has no files or leafdirs");
2909 }
2910
2911 /* Get the mean dir width of the fileset */
2912 if (attr = get_attr_integer(cmd, FSA_DIRWIDTH)) {
2913 fileset->fs_dirwidth = attr->attr_avd;
2914 } else {
2915 filebench_log(LOG_ERROR, "Fileset has zero directory width");
2916 fileset->fs_dirwidth = avd_int_alloc(0);
2917 }
2918
2919 /* Get the random variable for dir depth, if supplied */
2920 if (attr = get_attr_integer(cmd, FSA_DIRDEPTHRV)) {
2921 if (!AVD_IS_RANDOM(attr->attr_avd)) {
2922 filebench_log(LOG_ERROR,
2923 "Define fileset: dirdepthrv must be random var");
2924 filebench_shutdown(1);
2925 }
2926 fileset->fs_dirdepthrv = attr->attr_avd;
2927 } else {
2928 fileset->fs_dirdepthrv = NULL;
2929 }
2930
2931 /* Get the gamma value for dir depth distributions */
2932 if (attr = get_attr_integer(cmd, FSA_DIRGAMMA)) {
2933 if (AVD_IS_RANDOM(attr->attr_avd)) {
2934 filebench_log(LOG_ERROR,
2935 "Define fileset: dirgamma attr cannot be random");
2936 filebench_shutdown(1);
2937 }
2938 fileset->fs_dirgamma = attr->attr_avd;
2939 } else
2940 fileset->fs_dirgamma = avd_int_alloc(1500);
2941
2942 /* Get the gamma value for dir width distributions */
2943 if (attr = get_attr_integer(cmd, FSA_FILESIZEGAMMA)) {
2944 if (AVD_IS_RANDOM(attr->attr_avd)) {
2945 filebench_log(LOG_ERROR,
2946 "Define fileset: filesizegamma cannot be random");
2947 filebench_shutdown(1);
2948 }
2949 fileset->fs_sizegamma = attr->attr_avd;
2950 } else
2951 fileset->fs_sizegamma = avd_int_alloc(1500);
2952 }
2953
2954 /*
2955 * Creates and starts all defined procflow processes. The call to
2956 * procflow_init() results in creation of the requested number of
2957 * process instances for each previously defined procflow. The
2958 * child processes exec() a new instance of filebench, passing it
2959 * the instance number and address of the shared memory region.
2960 * The child processes will then create their threads and flowops.
2961 * The routine then unlocks the run_lock to allow all the processes'
2962 * threads to start and waits for all of them to begin execution.
2963 * Finally, it records the start time and resets the event generation
2964 * system.
2965 */
2966 static void
parser_proc_create(cmd_t * cmd)2967 parser_proc_create(cmd_t *cmd)
2968 {
2969 filebench_shm->shm_1st_err = 0;
2970 filebench_shm->shm_f_abort = FILEBENCH_OK;
2971
2972 if (procflow_init() != 0) {
2973 filebench_log(LOG_ERROR, "Failed to create processes\n");
2974 filebench_shutdown(1);
2975 }
2976
2977 /* Release the read lock, allowing threads to start */
2978 (void) pthread_rwlock_unlock(&filebench_shm->shm_run_lock);
2979
2980 /* Wait for all threads to start */
2981 if (procflow_allstarted() != 0) {
2982 filebench_log(LOG_ERROR, "Could not start run");
2983 return;
2984 }
2985
2986
2987 if (filebench_shm->shm_required &&
2988 (ipc_ismcreate(filebench_shm->shm_required) < 0)) {
2989 filebench_log(LOG_ERROR, "Could not allocate shared memory");
2990 return;
2991 }
2992
2993 filebench_shm->shm_starttime = gethrtime();
2994 eventgen_reset();
2995 }
2996
2997 /*
2998 * Calls fileset_createset() to populate all files and filesets and
2999 * create all associated, initially existant, files and subdirectories.
3000 * If errors are encountered, calls filebench_shutdown()
3001 * to exit filebench.
3002 */
3003 static void
parser_fileset_create(cmd_t * cmd)3004 parser_fileset_create(cmd_t *cmd)
3005 {
3006 if (!filecreate_done) {
3007 filecreate_done = 1;
3008
3009 /* initialize the random number system first */
3010 randdist_init();
3011
3012 /* create all the filesets */
3013 if (fileset_createset(NULL) != 0) {
3014 filebench_log(LOG_ERROR, "Failed to create filesets");
3015 filebench_shutdown(1);
3016 }
3017 } else {
3018 filebench_log(LOG_INFO,
3019 "Attempting to create fileset more than once, ignoring");
3020 }
3021
3022 }
3023
3024 /*
3025 * Deletes the files and directories that represent files and filesets on the
3026 * storage medium.
3027 */
3028 static void
parser_fileset_shutdown(cmd_t * cmd)3029 parser_fileset_shutdown(cmd_t *cmd)
3030 {
3031 filebench_log(LOG_INFO, "Shutting down filesets");
3032 fileset_delete_all_filesets();
3033 }
3034
3035 /*
3036 * Shuts down all processes and their associated threads. When finished
3037 * it deletes interprocess shared memory and resets the event generator.
3038 * It does not exit the filebench program though.
3039 */
3040 static void
parser_proc_shutdown(cmd_t * cmd)3041 parser_proc_shutdown(cmd_t *cmd)
3042 {
3043 filebench_log(LOG_INFO, "Shutting down processes");
3044 filecreate_done = 0;
3045 procflow_shutdown();
3046 if (filebench_shm->shm_required)
3047 ipc_ismdelete();
3048 eventgen_reset();
3049 }
3050
3051 /*
3052 * Ends filebench run after first destoring any interprocess
3053 * shared memory. The call to filebench_shutdown()
3054 * also causes filebench to exit.
3055 */
3056 static void
parser_filebench_shutdown(cmd_t * cmd)3057 parser_filebench_shutdown(cmd_t *cmd)
3058 {
3059 int f_abort = filebench_shm->shm_f_abort;
3060
3061 ipc_fini();
3062
3063 if (f_abort == FILEBENCH_ABORT_ERROR)
3064 filebench_shutdown(1);
3065 else
3066 filebench_shutdown(0);
3067 }
3068
3069 /*
3070 * This is Used for timing runs.Pauses the master thread in one second
3071 * intervals until the supplied ptime runs out or the f_abort flag
3072 * is raised. If given a time of zero or less, or the mode is stop on
3073 * lack of resources, it will pause until f_abort is raised.
3074 */
3075 static int
parser_pause(int ptime)3076 parser_pause(int ptime)
3077 {
3078 int timeslept = 0;
3079
3080 if ((filebench_shm->shm_rmode == FILEBENCH_MODE_TIMEOUT) &&
3081 (ptime > 0)) {
3082 while (timeslept < ptime) {
3083 (void) sleep(1);
3084 timeslept++;
3085 if (filebench_shm->shm_f_abort)
3086 break;
3087 }
3088 } else {
3089 /* initial runtime of 0 means run till abort */
3090 /* CONSTCOND */
3091 while (1) {
3092 (void) sleep(1);
3093 timeslept++;
3094 if (filebench_shm->shm_f_abort)
3095 break;
3096 }
3097 }
3098 return (timeslept);
3099 }
3100
3101 /*
3102 * Do a file bench run. Calls routines to create file sets, files, and
3103 * processes. It resets the statistics counters, then sleeps for the runtime
3104 * passed as an argument to it on the command line in 1 second increments.
3105 * When it is finished sleeping, it collects a snapshot of the statistics
3106 * and ends the run.
3107 */
3108 static void
parser_run(cmd_t * cmd)3109 parser_run(cmd_t *cmd)
3110 {
3111 int runtime;
3112 int timeslept;
3113
3114 runtime = cmd->cmd_qty;
3115
3116 parser_fileset_create(cmd);
3117 parser_proc_create(cmd);
3118
3119 /* check for startup errors */
3120 if (filebench_shm->shm_f_abort)
3121 return;
3122
3123 filebench_log(LOG_INFO, "Running...");
3124 stats_clear();
3125
3126 timeslept = parser_pause(runtime);
3127
3128 filebench_log(LOG_INFO, "Run took %d seconds...", timeslept);
3129 parser_statssnap(cmd);
3130 parser_proc_shutdown(cmd);
3131 }
3132
3133 /*
3134 * Similar to parser_run, but gets the sleep time from a variable
3135 * whose name is supplied as an argument to the command.
3136 */
3137 static void
parser_run_variable(cmd_t * cmd)3138 parser_run_variable(cmd_t *cmd)
3139 {
3140 avd_t integer = var_ref_attr(cmd->cmd_tgt1);
3141 int runtime;
3142 int timeslept;
3143
3144 if (integer == NULL) {
3145 filebench_log(LOG_ERROR, "Unknown variable %s",
3146 cmd->cmd_tgt1);
3147 return;
3148 }
3149
3150 runtime = avd_get_int(integer);
3151
3152 /* check for startup errors */
3153 if (filebench_shm->shm_f_abort)
3154 return;
3155
3156 filebench_log(LOG_INFO, "Running...");
3157 stats_clear();
3158
3159 timeslept = parser_pause(runtime);
3160
3161 filebench_log(LOG_INFO, "Run took %d seconds...", timeslept);
3162 parser_statssnap(cmd);
3163 parser_proc_shutdown(cmd);
3164 }
3165
3166 char *usagestr = NULL;
3167
3168 /*
3169 * Prints usage string if defined, else just a message requesting load of a
3170 * personality.
3171 */
3172 static void
parser_help(cmd_t * cmd)3173 parser_help(cmd_t *cmd)
3174 {
3175 if (usagestr) {
3176 filebench_log(LOG_INFO, "%s", usagestr);
3177 } else {
3178 filebench_log(LOG_INFO,
3179 "load <personality> (ls "
3180 "%s/workloads for list)", fbbasepath);
3181 }
3182 }
3183
3184 char *varstr = NULL;
3185
3186 /*
3187 * Prints the string of all var definitions, if there is one.
3188 */
3189 static void
parser_printvars(cmd_t * cmd)3190 parser_printvars(cmd_t *cmd)
3191 {
3192 char *str, *c;
3193
3194 if (varstr) {
3195 str = strdup(varstr);
3196 for (c = str; *c != '\0'; c++) {
3197 if ((char)*c == '$')
3198 *c = ' ';
3199 }
3200 filebench_log(LOG_INFO, "%s", str);
3201 free(str);
3202 }
3203 }
3204
3205 /*
3206 * Establishes multi-client synchronization socket with synch server.
3207 */
3208 static void
parser_enable_mc(cmd_t * cmd)3209 parser_enable_mc(cmd_t *cmd)
3210 {
3211 attr_t *attr;
3212 char *master;
3213 char *client;
3214
3215 if (attr= get_attr(cmd, FSA_MASTER)) {
3216 master = avd_get_str(attr->attr_avd);
3217 } else {
3218 filebench_log(LOG_ERROR,
3219 "enable multi: no master specified");
3220 return;
3221 }
3222
3223 if (attr= get_attr(cmd, FSA_CLIENT)) {
3224 client = avd_get_str(attr->attr_avd);
3225 } else {
3226 filebench_log(LOG_ERROR,
3227 "enable multi: no client specified");
3228 return;
3229 }
3230
3231 mc_sync_open_sock(master, 8001, client);
3232 }
3233
3234 /*
3235 * Exchanges multi-client synchronization message with synch server.
3236 */
3237 static void
parser_domultisync(cmd_t * cmd)3238 parser_domultisync(cmd_t *cmd)
3239 {
3240 attr_t *attr;
3241 fbint_t value;
3242
3243 if (attr = get_attr(cmd, FSA_VALUE))
3244 value = avd_get_int(attr->attr_avd);
3245 else
3246 value = 1;
3247
3248 mc_sync_synchronize((int)value);
3249 }
3250
3251 /*
3252 * Used by the SET command to add a var and default value string to the
3253 * varstr string. It allocates a new, larger varstr string, copies the
3254 * old contents of varstr into it, then adds the new var string on the end.
3255 */
3256 static void
parser_vars(cmd_t * cmd)3257 parser_vars(cmd_t *cmd)
3258 {
3259 char *string = cmd->cmd_tgt1;
3260 char *newvars;
3261
3262 if (string == NULL)
3263 return;
3264
3265 if (dofile)
3266 return;
3267
3268 if (varstr == NULL) {
3269 newvars = malloc(strlen(string) + 2);
3270 *newvars = 0;
3271 } else {
3272 newvars = malloc(strlen(varstr) + strlen(string) + 2);
3273 (void) strcpy(newvars, varstr);
3274 }
3275 (void) strcat(newvars, string);
3276 (void) strcat(newvars, " ");
3277
3278 if (varstr)
3279 free(varstr);
3280
3281 varstr = newvars;
3282 }
3283
3284 /*
3285 * used by the set command to set the integer part of a regular
3286 * variable, or the appropriate field of a random variable
3287 */
3288 static void
parser_set_integer(cmd_t * cmd)3289 parser_set_integer(cmd_t *cmd)
3290 {
3291 var_assign_integer(cmd->cmd_tgt1, cmd->cmd_qty);
3292 }
3293
3294 /*
3295 * used by the set command to set the integer part of a regular
3296 * variable from another variable, or the appropriate field of a
3297 * random variable from another variable
3298 */
3299 static void
parser_set_var(cmd_t * cmd)3300 parser_set_var(cmd_t *cmd)
3301 {
3302 var_assign_var(cmd->cmd_tgt1, cmd->cmd_tgt2);
3303 }
3304
3305 /*
3306 * Used by the set command to set up for a binary operation of a
3307 * variable from a var, with an integer
3308 */
3309 static void
parser_set_var_op_int(cmd_t * cmd)3310 parser_set_var_op_int(cmd_t *cmd)
3311 {
3312 printf("parser_set_var_op_int: Called\n");
3313 switch (cmd->cmd_subtype) {
3314 case FSK_PLUS:
3315 var_assign_op_var_int(cmd->cmd_tgt1, VAR_IND_INT_SUM_IV,
3316 cmd->cmd_tgt2, cmd->cmd_qty);
3317 break;
3318
3319 case FSK_MINUS:
3320 var_assign_op_var_int(cmd->cmd_tgt1, VAR_IND_IV_DIF_INT,
3321 cmd->cmd_tgt2, cmd->cmd_qty);
3322 break;
3323
3324 case FSK_MULTIPLY:
3325 var_assign_op_var_int(cmd->cmd_tgt1, VAR_IND_INT_MUL_IV,
3326 cmd->cmd_tgt2, cmd->cmd_qty);
3327 break;
3328
3329 case FSK_DIVIDE:
3330 var_assign_op_var_int(cmd->cmd_tgt1, VAR_IND_IV_DIV_INT,
3331 cmd->cmd_tgt2, cmd->cmd_qty);
3332 break;
3333 }
3334 }
3335
3336 /*
3337 * Used by the set command to set up for a binary operation of an
3338 * integer with a variable from a var
3339 */
3340 static void
parser_set_int_op_var(cmd_t * cmd)3341 parser_set_int_op_var(cmd_t *cmd)
3342 {
3343 switch (cmd->cmd_subtype) {
3344 case FSK_PLUS:
3345 var_assign_op_var_int(cmd->cmd_tgt1, VAR_IND_INT_SUM_IV,
3346 cmd->cmd_tgt3, cmd->cmd_qty);
3347 break;
3348
3349 case FSK_MINUS:
3350 var_assign_op_var_int(cmd->cmd_tgt1, VAR_IND_INT_DIF_IV,
3351 cmd->cmd_tgt3, cmd->cmd_qty);
3352 break;
3353
3354 case FSK_MULTIPLY:
3355 var_assign_op_var_int(cmd->cmd_tgt1, VAR_IND_INT_MUL_IV,
3356 cmd->cmd_tgt3, cmd->cmd_qty);
3357 break;
3358
3359 case FSK_DIVIDE:
3360 var_assign_op_var_int(cmd->cmd_tgt1, VAR_IND_INT_DIV_IV,
3361 cmd->cmd_tgt3, cmd->cmd_qty);
3362 break;
3363 }
3364 }
3365
3366 /*
3367 * Used by the set command to set up for a binary operation of two
3368 * variables from other vars.
3369 */
3370 static void
parser_set_var_op_var(cmd_t * cmd)3371 parser_set_var_op_var(cmd_t *cmd)
3372 {
3373 switch (cmd->cmd_subtype) {
3374 case FSK_PLUS:
3375 var_assign_op_var_var(cmd->cmd_tgt1, VAR_IND_IV_SUM_IV,
3376 cmd->cmd_tgt2, cmd->cmd_tgt3);
3377 break;
3378
3379 case FSK_MINUS:
3380 var_assign_op_var_var(cmd->cmd_tgt1, VAR_IND_IV_DIF_IV,
3381 cmd->cmd_tgt2, cmd->cmd_tgt3);
3382 break;
3383
3384 case FSK_MULTIPLY:
3385 var_assign_op_var_var(cmd->cmd_tgt1, VAR_IND_IV_MUL_IV,
3386 cmd->cmd_tgt2, cmd->cmd_tgt3);
3387 break;
3388
3389 case FSK_DIVIDE:
3390 var_assign_op_var_var(cmd->cmd_tgt1, VAR_IND_IV_DIV_IV,
3391 cmd->cmd_tgt2, cmd->cmd_tgt3);
3392 break;
3393 }
3394 }
3395
3396
3397 /*
3398 * Sleeps for cmd->cmd_qty seconds, one second at a time.
3399 */
3400 static void
parser_warmup(cmd_t * cmd)3401 parser_warmup(cmd_t *cmd)
3402 {
3403 int sleeptime;
3404
3405 /* check for startup errors */
3406 if (filebench_shm->shm_f_abort)
3407 return;
3408
3409 sleeptime = cmd->cmd_qty;
3410 filebench_log(LOG_INFO, "Warming up...");
3411
3412 (void) parser_pause(sleeptime);
3413 }
3414
3415 /*
3416 * Same as parser_sleep, except the sleep time is obtained from a variable
3417 * whose name is passed to it as an argument on the command line.
3418 */
3419 static void
parser_warmup_variable(cmd_t * cmd)3420 parser_warmup_variable(cmd_t *cmd)
3421 {
3422 avd_t integer = var_ref_attr(cmd->cmd_tgt1);
3423 int sleeptime;
3424
3425 if (integer == NULL) {
3426 filebench_log(LOG_ERROR, "Unknown variable %s",
3427 cmd->cmd_tgt1);
3428 return;
3429 }
3430
3431 sleeptime = avd_get_int(integer);
3432
3433 /* check for startup errors */
3434 if (filebench_shm->shm_f_abort)
3435 return;
3436
3437 filebench_log(LOG_INFO, "Warming up...");
3438
3439 (void) parser_pause(sleeptime);
3440 }
3441
3442 /*
3443 * Sleeps for cmd->cmd_qty seconds, one second at a time.
3444 */
3445 static void
parser_sleep(cmd_t * cmd)3446 parser_sleep(cmd_t *cmd)
3447 {
3448 int sleeptime;
3449 int timeslept;
3450
3451 /* check for startup errors */
3452 if (filebench_shm->shm_f_abort)
3453 return;
3454
3455 sleeptime = cmd->cmd_qty;
3456 filebench_log(LOG_INFO, "Running...");
3457
3458 timeslept = parser_pause(sleeptime);
3459
3460 filebench_log(LOG_INFO, "Run took %d seconds...", timeslept);
3461 }
3462
3463 /*
3464 * Same as parser_sleep, except the sleep time is obtained from a variable
3465 * whose name is passed to it as an argument on the command line.
3466 */
3467 static void
parser_sleep_variable(cmd_t * cmd)3468 parser_sleep_variable(cmd_t *cmd)
3469 {
3470 avd_t integer = var_ref_attr(cmd->cmd_tgt1);
3471 int sleeptime;
3472 int timeslept;
3473
3474 if (integer == NULL) {
3475 filebench_log(LOG_ERROR, "Unknown variable %s",
3476 cmd->cmd_tgt1);
3477 return;
3478 }
3479
3480 sleeptime = avd_get_int(integer);
3481
3482 /* check for startup errors */
3483 if (filebench_shm->shm_f_abort)
3484 return;
3485
3486 filebench_log(LOG_INFO, "Running...");
3487
3488 timeslept = parser_pause(sleeptime);
3489
3490 filebench_log(LOG_INFO, "Run took %d seconds...", timeslept);
3491 }
3492
3493 /*
3494 * Parser log prints the values of a list of variables to the log file.
3495 * The list of variables is placed on the command line, separated
3496 * by comas and the entire list is enclosed in quotes.
3497 * For example, if $dir contains "/export/home/tmp" and $filesize = 1048576,
3498 * then typing: log "$dir, $filesize" prints: log /export/home/tmp, 1048576
3499 */
3500 static void
parser_log(cmd_t * cmd)3501 parser_log(cmd_t *cmd)
3502 {
3503 char *string;
3504
3505 if (cmd->cmd_param_list == NULL)
3506 return;
3507
3508 string = parser_list2string(cmd->cmd_param_list);
3509
3510 if (string == NULL)
3511 return;
3512
3513 filebench_log(LOG_VERBOSE, "log %s", string);
3514 filebench_log(LOG_LOG, "%s", string);
3515 }
3516
3517 /*
3518 * Implements the stats directory command. changes the directory for
3519 * dumping statistics to supplied directory path. For example:
3520 * stats directory /tmp
3521 * changes the stats directory to "/tmp".
3522 */
3523 static void
parser_directory(cmd_t * cmd)3524 parser_directory(cmd_t *cmd)
3525 {
3526 char newdir[MAXPATHLEN];
3527 char *dir;
3528
3529 if ((dir = parser_list2string(cmd->cmd_param_list)) == NULL) {
3530 filebench_log(LOG_ERROR, "Cannot interpret directory");
3531 return;
3532 }
3533
3534 *newdir = 0;
3535 /* Change dir relative to cwd if path not fully qualified */
3536 if (*dir != '/') {
3537 (void) strcat(newdir, cwd);
3538 (void) strcat(newdir, "/");
3539 }
3540 (void) strcat(newdir, dir);
3541 (void) mkdir(newdir, 0755);
3542 filebench_log(LOG_VERBOSE, "Change dir to %s", newdir);
3543 chdir(newdir);
3544 free(dir);
3545 }
3546
3547 #define PIPE_PARENT 1
3548 #define PIPE_CHILD 0
3549
3550 /*
3551 * Runs the quoted unix command as a background process. Intended for
3552 * running statistics gathering utilities such as mpstat while the filebench
3553 * workload is running. Also records the pid's of the background processes
3554 * so that parser_statssnap() can terminate them when the run completes.
3555 */
3556 static void
parser_statscmd(cmd_t * cmd)3557 parser_statscmd(cmd_t *cmd)
3558 {
3559 char *string;
3560 pid_t pid;
3561 pidlist_t *pidlistent;
3562 int pipe_fd[2];
3563 int newstdout;
3564
3565 if (cmd->cmd_param_list == NULL)
3566 return;
3567
3568 string = parser_list2string(cmd->cmd_param_list);
3569
3570 if (string == NULL)
3571 return;
3572
3573 if ((pipe(pipe_fd)) < 0) {
3574 filebench_log(LOG_ERROR, "statscmd pipe failed");
3575 return;
3576 }
3577
3578 #ifdef HAVE_FORK1
3579 if ((pid = fork1()) < 0) {
3580 filebench_log(LOG_ERROR, "statscmd fork failed");
3581 return;
3582 }
3583 #elif HAVE_FORK
3584 if ((pid = fork()) < 0) {
3585 filebench_log(LOG_ERROR, "statscmd fork failed");
3586 return;
3587 }
3588 #else
3589 Crash! - Need code to deal with no fork1!
3590 #endif /* HAVE_FORK1 */
3591
3592 if (pid == 0) {
3593
3594 setsid();
3595
3596 filebench_log(LOG_VERBOSE,
3597 "Backgrounding %s", string);
3598 /*
3599 * Child
3600 * - close stdout
3601 * - dup to create new stdout
3602 * - close pipe fds
3603 */
3604 (void) close(1);
3605
3606 if ((newstdout = dup(pipe_fd[PIPE_CHILD])) < 0) {
3607 filebench_log(LOG_ERROR,
3608 "statscmd dup failed: %s",
3609 strerror(errno));
3610 }
3611
3612 (void) close(pipe_fd[PIPE_PARENT]);
3613 (void) close(pipe_fd[PIPE_CHILD]);
3614
3615 if (system(string) < 0) {
3616 filebench_log(LOG_ERROR,
3617 "statscmd exec failed: %s",
3618 strerror(errno));
3619 }
3620 /* Failed! */
3621 exit(1);
3622
3623 } else {
3624
3625 /* Record pid in pidlist for subsequent reaping by stats snap */
3626 if ((pidlistent = (pidlist_t *)malloc(sizeof (pidlist_t)))
3627 == NULL) {
3628 filebench_log(LOG_ERROR, "pidlistent malloc failed");
3629 return;
3630 }
3631
3632 pidlistent->pl_pid = pid;
3633 pidlistent->pl_fd = pipe_fd[PIPE_PARENT];
3634 (void) close(pipe_fd[PIPE_CHILD]);
3635
3636 /* Add fileobj to global list */
3637 if (pidlist == NULL) {
3638 pidlist = pidlistent;
3639 pidlistent->pl_next = NULL;
3640 } else {
3641 pidlistent->pl_next = pidlist;
3642 pidlist = pidlistent;
3643 }
3644 }
3645 }
3646
3647 /*
3648 * Launches a shell to run the unix command supplied in the argument.
3649 * The command should be enclosed in quotes, as in:
3650 * system "rm xyz"
3651 * which would run the "rm" utility to delete the file "xyz".
3652 */
3653 static void
parser_system(cmd_t * cmd)3654 parser_system(cmd_t *cmd)
3655 {
3656 char *string;
3657
3658 if (cmd->cmd_param_list == NULL)
3659 return;
3660
3661 string = parser_list2string(cmd->cmd_param_list);
3662
3663 if (string == NULL)
3664 return;
3665
3666 filebench_log(LOG_VERBOSE,
3667 "Running '%s'", string);
3668
3669 if (system(string) < 0) {
3670 filebench_log(LOG_ERROR,
3671 "system exec failed: %s",
3672 strerror(errno));
3673 filebench_shutdown(1);
3674 }
3675 free(string);
3676 }
3677
3678 /*
3679 * Echos string supplied with command to the log.
3680 */
3681 static void
parser_echo(cmd_t * cmd)3682 parser_echo(cmd_t *cmd)
3683 {
3684 char *string;
3685
3686 if (cmd->cmd_param_list == NULL)
3687 return;
3688
3689 string = parser_list2string(cmd->cmd_param_list);
3690
3691 if (string == NULL)
3692 return;
3693
3694 filebench_log(LOG_INFO, "%s", string);
3695 }
3696
3697 /*
3698 * Checks to see if the specified data directory exists and it's mounted file
3699 * system is the correct type.
3700 */
3701 static void
parser_fscheck(cmd_t * cmd)3702 parser_fscheck(cmd_t *cmd)
3703 {
3704 int fstype_idx;
3705 char *pathname = NULL;
3706 char *filesys = "tmpfs";
3707 char string[MAXPATHLEN];
3708 struct statvfs64 statbuf;
3709 attr_t *attr;
3710
3711 if (cmd->cmd_attr_list == NULL)
3712 return;
3713
3714 for (attr = cmd->cmd_attr_list; attr; attr = attr->attr_next) {
3715
3716 switch(attr->attr_name) {
3717 case FSA_PATH:
3718 pathname = avd_get_str(attr->attr_avd);
3719 break;
3720 case FSA_FSTYPE:
3721 filesys = avd_get_str(attr->attr_avd);
3722 break;
3723 }
3724 }
3725
3726 if (pathname == NULL)
3727 return;
3728
3729 if (statvfs64(pathname, &statbuf) < 0) {
3730 filebench_log(LOG_ERROR,
3731 "%s error with supplied data path name: %s; exiting",
3732 strerror(errno), pathname);
3733 filebench_shutdown(1);
3734 return;
3735 }
3736
3737 if (strncmp(filesys, statbuf.f_basetype, FSTYPSZ) != 0) {
3738 filebench_log(LOG_ERROR,
3739 "File System is of type %s, NOT %s as indicated",
3740 statbuf.f_basetype, filesys);
3741 filebench_shutdown(1);
3742 return;
3743 }
3744 }
3745
3746 /*
3747 * Checks to see if any filesets need to have their caches flushed, and
3748 * if so invokes the fs_flush script.
3749 */
3750 static void
parser_fsflush(cmd_t * cmd)3751 parser_fsflush(cmd_t *cmd)
3752 {
3753 fileset_t *fileset;
3754 char **fspathlist;
3755 char *pathname = NULL;
3756 char *filesys = NULL;
3757 char string[MAXPATHLEN];
3758 attr_t *attr;
3759 int fsidx;
3760
3761 if ((attr = cmd->cmd_attr_list) == NULL)
3762 return;
3763
3764 /* Get supplied file system type */
3765 if (attr->attr_name == FSA_FSTYPE)
3766 filesys = avd_get_str(attr->attr_avd);
3767
3768 if (filesys == NULL) {
3769 filebench_log(LOG_ERROR,
3770 "FSFLUSH command lacks file system type");
3771 return;
3772 }
3773
3774 /* Check all filesets for any that remain cached and count them*/
3775 fsidx = 0;
3776 for (fileset = filebench_shm->shm_filesetlist; fileset != NULL;
3777 fileset = fileset->fs_next) {
3778
3779 if (avd_get_bool(fileset->fs_cached))
3780 return;
3781
3782 fsidx++;
3783 }
3784
3785 /* allocated space for fileset path pointers */
3786 fspathlist = (char **)malloc(fsidx * sizeof(char *));
3787
3788 /* If flushing still required, flush all filesets */
3789 fsidx = 0;
3790 for (fileset = filebench_shm->shm_filesetlist; fileset != NULL;
3791 fileset = fileset->fs_next) {
3792 int idx;
3793
3794 if ((pathname = avd_get_str(fileset->fs_path)) == NULL)
3795 return;
3796
3797 for (idx = 0; idx < fsidx; idx++) {
3798 if (strcmp(pathname, fspathlist[idx]) == 0)
3799 break;
3800 }
3801
3802 if (fsidx == idx) {
3803
3804 /* found a new path */
3805 fspathlist[fsidx++] = pathname;
3806
3807 /* now flush it */
3808 snprintf(string, MAXPATHLEN,
3809 "%s/scripts/fs_flush %s %s", fbbasepath,
3810 filesys, pathname);
3811
3812 if (system(string) < 0) {
3813 filebench_log(LOG_ERROR,
3814 "exec of fs_flush script failed: %s",
3815 strerror(errno));
3816 filebench_shutdown(1);
3817 }
3818 }
3819 }
3820 }
3821
3822 /*
3823 * Prints out the version of FileBench.
3824 */
3825 static void
parser_version(cmd_t * cmd)3826 parser_version(cmd_t *cmd)
3827 {
3828 filebench_log(LOG_INFO, "FileBench Version: %s", FILEBENCH_VERSION);
3829 }
3830
3831 /*
3832 * Adds the string supplied as the argument to the usage command
3833 * to the end of the string printed by the help command.
3834 */
3835 static void
parser_usage(cmd_t * cmd)3836 parser_usage(cmd_t *cmd)
3837 {
3838 char *string;
3839 char *newusage;
3840
3841 if (cmd->cmd_param_list == NULL)
3842 return;
3843
3844 string = parser_list2string(cmd->cmd_param_list);
3845
3846 if (string == NULL)
3847 return;
3848
3849 if (dofile)
3850 return;
3851
3852 if (usagestr == NULL) {
3853 newusage = malloc(strlen(string) + 2);
3854 *newusage = 0;
3855 } else {
3856 newusage = malloc(strlen(usagestr) + strlen(string) + 2);
3857 (void) strcpy(newusage, usagestr);
3858 }
3859 (void) strcat(newusage, "\n");
3860 (void) strcat(newusage, string);
3861
3862 if (usagestr)
3863 free(usagestr);
3864
3865 usagestr = newusage;
3866
3867 filebench_log(LOG_INFO, "%s", string);
3868 }
3869
3870 /*
3871 * Updates the global dump filename with the filename supplied
3872 * as the command's argument. Then dumps the statistics of each
3873 * worker flowop into the dump file, followed by a summary of
3874 * overall totals.
3875 */
3876 static void
parser_statsdump(cmd_t * cmd)3877 parser_statsdump(cmd_t *cmd)
3878 {
3879 char *string;
3880
3881 if (cmd->cmd_param_list == NULL)
3882 return;
3883
3884 string = parser_list2string(cmd->cmd_param_list);
3885
3886 if (string == NULL)
3887 return;
3888
3889 filebench_log(LOG_VERBOSE,
3890 "Stats dump to file '%s'", string);
3891
3892 stats_dump(string);
3893
3894 free(string);
3895 }
3896
3897 /*
3898 * Same as statsdump, but outputs in a computer friendly format.
3899 */
3900 static void
parser_statsmultidump(cmd_t * cmd)3901 parser_statsmultidump(cmd_t *cmd)
3902 {
3903 char *string;
3904
3905 if (cmd->cmd_param_list == NULL)
3906 return;
3907
3908 string = parser_list2string(cmd->cmd_param_list);
3909
3910 if (string == NULL)
3911 return;
3912
3913 filebench_log(LOG_VERBOSE,
3914 "Stats dump to file '%s'", string);
3915
3916 stats_multidump(string);
3917
3918 free(string);
3919 }
3920
3921 /*
3922 * Same as parser_statsdump, but in xml format.
3923 */
3924 static void
parser_statsxmldump(cmd_t * cmd)3925 parser_statsxmldump(cmd_t *cmd)
3926 {
3927 char *string;
3928
3929 if (cmd->cmd_param_list == NULL)
3930 return;
3931
3932 string = parser_list2string(cmd->cmd_param_list);
3933
3934 if (string == NULL)
3935 return;
3936
3937 filebench_log(LOG_VERBOSE,
3938 "Stats dump to file '%s'", string);
3939
3940 stats_xmldump(string);
3941
3942 free(string);
3943 }
3944
3945 /*
3946 * Kills off background statistics collection processes, then takes a snapshot
3947 * of the filebench run's collected statistics using stats_snap() from
3948 * stats.c.
3949 */
3950 static void
parser_statssnap(cmd_t * cmd)3951 parser_statssnap(cmd_t *cmd)
3952 {
3953 pidlist_t *pidlistent;
3954 int stat;
3955 pid_t pid;
3956
3957 for (pidlistent = pidlist; pidlistent != NULL;
3958 pidlistent = pidlistent->pl_next) {
3959 filebench_log(LOG_VERBOSE, "Killing session %d for pid %d",
3960 getsid(pidlistent->pl_pid),
3961 pidlistent->pl_pid);
3962 if (pidlistent->pl_fd)
3963 (void) close(pidlistent->pl_fd);
3964 #ifdef HAVE_SIGSEND
3965 sigsend(P_SID, getsid(pidlistent->pl_pid), SIGTERM);
3966 #else
3967 (void) kill(-1, SIGTERM);
3968 #endif
3969
3970 /* Close pipe */
3971 if (pidlistent->pl_fd)
3972 (void) close(pidlistent->pl_fd);
3973
3974 /* Wait for cmd and all its children */
3975 while ((pid = waitpid(pidlistent->pl_pid * -1, &stat, 0)) > 0)
3976 filebench_log(LOG_DEBUG_IMPL,
3977 "Waited for pid %d", (int)pid);
3978 }
3979
3980 for (pidlistent = pidlist; pidlistent != NULL;
3981 pidlistent = pidlistent->pl_next) {
3982 free(pidlistent);
3983 }
3984
3985 pidlist = NULL;
3986 stats_snap();
3987 }
3988
3989 /*
3990 * Shutdown filebench.
3991 */
3992 static void
parser_abort(int arg)3993 parser_abort(int arg)
3994 {
3995 (void) sigignore(SIGINT);
3996 filebench_log(LOG_INFO, "Aborting...");
3997 filebench_shutdown(1);
3998 }
3999
4000 /*
4001 * define a random variable and initialize the distribution parameters
4002 */
4003 static void
parser_randvar_define(cmd_t * cmd)4004 parser_randvar_define(cmd_t *cmd)
4005 {
4006 var_t *var;
4007 randdist_t *rndp;
4008 attr_t *attr;
4009 char *name;
4010
4011 /* Get the name for the random variable */
4012 if (attr = get_attr(cmd, FSA_NAME)) {
4013 name = avd_get_str(attr->attr_avd);
4014 } else {
4015 filebench_log(LOG_ERROR,
4016 "define randvar: no name specified");
4017 return;
4018 }
4019
4020 if ((var = var_define_randvar(name)) == NULL) {
4021 filebench_log(LOG_ERROR,
4022 "define randvar: failed for random variable %s",
4023 name);
4024 return;
4025 }
4026
4027 rndp = var->var_val.randptr;
4028 rndp->rnd_type = 0;
4029
4030 /* Get the source of the random numbers */
4031 if (attr = get_attr_integer(cmd, FSA_RANDSRC)) {
4032 int randsrc = (int)avd_get_int(attr->attr_avd);
4033
4034 switch (randsrc) {
4035 case FSV_URAND:
4036 rndp->rnd_type |= RAND_SRC_URANDOM;
4037 break;
4038 case FSV_RAND48:
4039 rndp->rnd_type |= RAND_SRC_GENERATOR;
4040 break;
4041 }
4042 } else {
4043 /* default to rand48 random number generator */
4044 rndp->rnd_type |= RAND_SRC_GENERATOR;
4045 }
4046
4047 /* Get the min value of the random distribution */
4048 if (attr = get_attr_integer(cmd, FSA_RANDMIN))
4049 rndp->rnd_min = attr->attr_avd;
4050 else
4051 rndp->rnd_min = avd_int_alloc(0);
4052
4053 /* Get the roundoff value for the random distribution */
4054 if (attr = get_attr_integer(cmd, FSA_RANDROUND))
4055 rndp->rnd_round = attr->attr_avd;
4056 else
4057 rndp->rnd_round = avd_int_alloc(0);
4058
4059 /* Get a tablular probablility distribution if there is one */
4060 if (attr = get_attr(cmd, FSA_RANDTABLE)) {
4061 rndp->rnd_probtabs = (probtabent_t *)(attr->attr_obj);
4062 rndp->rnd_type |= RAND_TYPE_TABLE;
4063
4064 /* no need for the rest of the attributes */
4065 return;
4066 } else {
4067 rndp->rnd_probtabs = NULL;
4068 }
4069
4070 /* Get the type for the random variable */
4071 if (attr = get_attr(cmd, FSA_TYPE)) {
4072 int disttype = (int)avd_get_int(attr->attr_avd);
4073
4074 switch (disttype) {
4075 case FSV_RANDUNI:
4076 rndp->rnd_type |= RAND_TYPE_UNIFORM;
4077 break;
4078 case FSA_RANDGAMMA:
4079 rndp->rnd_type |= RAND_TYPE_GAMMA;
4080 break;
4081 case FSV_RANDTAB:
4082 filebench_log(LOG_ERROR,
4083 "Table distribution type without prob table");
4084 break;
4085 }
4086 } else {
4087 /* default to gamma distribution type */
4088 rndp->rnd_type |= RAND_TYPE_GAMMA;
4089 }
4090
4091 /* Get the seed for the random variable */
4092 if (attr = get_attr_integer(cmd, FSA_RANDSEED))
4093 rndp->rnd_seed = attr->attr_avd;
4094 else
4095 rndp->rnd_seed = avd_int_alloc(0);
4096
4097 /* Get the gamma value of the random distribution */
4098 if (attr = get_attr_integer(cmd, FSA_RANDGAMMA))
4099 rndp->rnd_gamma = attr->attr_avd;
4100 else
4101 rndp->rnd_gamma = avd_int_alloc(1500);
4102
4103 /* Get the mean value of the random distribution */
4104 if (attr = get_attr_integer(cmd, FSA_RANDMEAN)) {
4105 rndp->rnd_mean = attr->attr_avd;
4106 } else if ((rndp->rnd_type & RAND_TYPE_MASK) == RAND_TYPE_GAMMA) {
4107 rndp->rnd_mean = NULL;
4108 } else {
4109 rndp->rnd_mean = avd_int_alloc(0);
4110 }
4111 }
4112
4113 /*
4114 * Set a specified random distribution parameter in a random variable.
4115 */
4116 static void
parser_randvar_set(cmd_t * cmd)4117 parser_randvar_set(cmd_t *cmd)
4118 {
4119 var_t *src_var, *randvar;
4120 randdist_t *rndp;
4121 avd_t value;
4122
4123 if ((randvar = var_find_randvar(cmd->cmd_tgt1)) == NULL) {
4124 filebench_log(LOG_ERROR,
4125 "set randvar: failed",
4126 cmd->cmd_tgt1);
4127 return;
4128 }
4129
4130 rndp = randvar->var_val.randptr;
4131 value = cmd->cmd_attr_list->attr_avd;
4132
4133 switch (cmd->cmd_qty) {
4134 case FSS_TYPE:
4135 {
4136 int disttype = (int)avd_get_int(value);
4137
4138 rndp->rnd_type &= (~RAND_TYPE_MASK);
4139
4140 switch (disttype) {
4141 case FSV_RANDUNI:
4142 rndp->rnd_type |= RAND_TYPE_UNIFORM;
4143 break;
4144 case FSA_RANDGAMMA:
4145 rndp->rnd_type |= RAND_TYPE_GAMMA;
4146 break;
4147 case FSV_RANDTAB:
4148 rndp->rnd_type |= RAND_TYPE_TABLE;
4149 break;
4150 }
4151 break;
4152 }
4153
4154 case FSS_SRC:
4155 {
4156 int randsrc = (int)avd_get_int(value);
4157
4158 rndp->rnd_type &=
4159 (~(RAND_SRC_URANDOM | RAND_SRC_GENERATOR));
4160
4161 switch (randsrc) {
4162 case FSV_URAND:
4163 rndp->rnd_type |= RAND_SRC_URANDOM;
4164 break;
4165 case FSV_RAND48:
4166 rndp->rnd_type |= RAND_SRC_GENERATOR;
4167 break;
4168 }
4169 break;
4170 }
4171
4172 case FSS_SEED:
4173 rndp->rnd_seed = value;
4174 break;
4175
4176 case FSS_GAMMA:
4177 rndp->rnd_gamma = value;
4178 break;
4179
4180 case FSS_MEAN:
4181 rndp->rnd_mean = value;
4182 break;
4183
4184 case FSS_MIN:
4185 rndp->rnd_min = value;
4186 break;
4187
4188 case FSS_ROUND:
4189 rndp->rnd_round = value;
4190 break;
4191
4192 default:
4193 filebench_log(LOG_ERROR, "setrandvar: undefined attribute");
4194 }
4195 }
4196
4197 /*
4198 * alloc_cmd() allocates the required resources for a cmd_t. On failure, a
4199 * filebench_log is issued and NULL is returned.
4200 */
4201 static cmd_t *
alloc_cmd(void)4202 alloc_cmd(void)
4203 {
4204 cmd_t *cmd;
4205
4206 if ((cmd = malloc(sizeof (cmd_t))) == NULL) {
4207 filebench_log(LOG_ERROR, "Alloc cmd failed");
4208 return (NULL);
4209 }
4210
4211 (void) memset(cmd, 0, sizeof (cmd_t));
4212
4213 return (cmd);
4214 }
4215
4216 /*
4217 * Frees the resources of a cmd_t and then the cmd_t "cmd" itself.
4218 */
4219 static void
free_cmd(cmd_t * cmd)4220 free_cmd(cmd_t *cmd)
4221 {
4222 free((void *)cmd->cmd_tgt1);
4223 free((void *)cmd->cmd_tgt2);
4224 free(cmd);
4225 }
4226
4227 /*
4228 * Allocates an attr_t structure and zeros it. Returns NULL on failure, or
4229 * a pointer to the attr_t.
4230 */
4231 static attr_t *
alloc_attr(void)4232 alloc_attr(void)
4233 {
4234 attr_t *attr;
4235
4236 if ((attr = malloc(sizeof (attr_t))) == NULL) {
4237 return (NULL);
4238 }
4239
4240 (void) memset(attr, 0, sizeof (attr_t));
4241 return (attr);
4242 }
4243
4244 /*
4245 * Allocates a probtabent_t structure and zeros it. Returns NULL on failure, or
4246 * a pointer to the probtabent_t.
4247 */
4248 static probtabent_t *
alloc_probtabent(void)4249 alloc_probtabent(void)
4250 {
4251 probtabent_t *rte;
4252
4253 if ((rte = malloc(sizeof (probtabent_t))) == NULL) {
4254 return (NULL);
4255 }
4256
4257 (void) memset(rte, 0, sizeof (probtabent_t));
4258 return (rte);
4259 }
4260
4261 /*
4262 * Allocates an attr_t structure and puts the supplied var_t into
4263 * its attr_avd location, and sets its name to FSA_LVAR_ASSIGN
4264 */
4265 static attr_t *
alloc_lvar_attr(var_t * var)4266 alloc_lvar_attr(var_t *var)
4267 {
4268 attr_t *attr;
4269
4270 if ((attr = alloc_attr()) == NULL)
4271 return (NULL);
4272
4273 attr->attr_name = FSA_LVAR_ASSIGN;
4274 attr->attr_avd = (avd_t)var;
4275
4276 return (attr);
4277 }
4278
4279
4280 /*
4281 * Searches the attribute list for the command for the named attribute type.
4282 * The attribute list is created by the parser from the list of attributes
4283 * supplied with certain commands, such as the define and flowop commands.
4284 * Returns a pointer to the attribute structure if the named attribute is
4285 * found, otherwise returns NULL. If the attribute includes a parameter list,
4286 * the list is converted to a string and stored in the attr_avd field of
4287 * the returned attr_t struct.
4288 */
4289 static attr_t *
get_attr_fileset(cmd_t * cmd,int64_t name)4290 get_attr_fileset(cmd_t *cmd, int64_t name)
4291 {
4292 attr_t *attr;
4293 attr_t *rtn = NULL;
4294 char *string;
4295
4296 for (attr = cmd->cmd_attr_list; attr != NULL;
4297 attr = attr->attr_next) {
4298 filebench_log(LOG_DEBUG_IMPL,
4299 "attr %d = %d %llx?",
4300 attr->attr_name,
4301 name,
4302 attr->attr_avd);
4303
4304 if (attr->attr_name == name)
4305 rtn = attr;
4306 }
4307
4308 if (rtn == NULL)
4309 return (NULL);
4310
4311 if (rtn->attr_param_list) {
4312 filebench_log(LOG_DEBUG_SCRIPT, "attr is param list");
4313 rtn->attr_avd = parser_list2varstring(rtn->attr_param_list);
4314 }
4315
4316 return (rtn);
4317 }
4318
4319
4320 /*
4321 * Searches the attribute list for the command for the named attribute type.
4322 * The attribute list is created by the parser from the list of attributes
4323 * supplied with certain commands, such as the define and flowop commands.
4324 * Returns a pointer to the attribute structure if the named attribute is
4325 * found, otherwise returns NULL. If the attribute includes a parameter list,
4326 * the list is converted to a string and stored in the attr_avd field of
4327 * the returned attr_t struct.
4328 */
4329 static attr_t *
get_attr(cmd_t * cmd,int64_t name)4330 get_attr(cmd_t *cmd, int64_t name)
4331 {
4332 attr_t *attr;
4333 attr_t *rtn = NULL;
4334 char *string;
4335
4336 for (attr = cmd->cmd_attr_list; attr != NULL;
4337 attr = attr->attr_next) {
4338 filebench_log(LOG_DEBUG_IMPL,
4339 "attr %d = %d %llx?",
4340 attr->attr_name,
4341 name,
4342 attr->attr_avd);
4343
4344 if (attr->attr_name == name)
4345 rtn = attr;
4346 }
4347
4348 if (rtn == NULL)
4349 return (NULL);
4350
4351 if (rtn->attr_param_list) {
4352 filebench_log(LOG_DEBUG_SCRIPT, "attr is param list");
4353 string = parser_list2string(rtn->attr_param_list);
4354 if (string != NULL) {
4355 rtn->attr_avd = avd_str_alloc(string);
4356 filebench_log(LOG_DEBUG_SCRIPT,
4357 "attr string %s", string);
4358 }
4359 }
4360
4361 return (rtn);
4362 }
4363
4364 /*
4365 * Similar to get_attr, but converts the parameter string supplied with the
4366 * named attribute to an integer and stores the integer in the attr_avd
4367 * portion of the returned attr_t struct.
4368 */
4369 static attr_t *
get_attr_integer(cmd_t * cmd,int64_t name)4370 get_attr_integer(cmd_t *cmd, int64_t name)
4371 {
4372 attr_t *attr;
4373 attr_t *rtn = NULL;
4374
4375 for (attr = cmd->cmd_attr_list; attr != NULL;
4376 attr = attr->attr_next) {
4377 if (attr->attr_name == name)
4378 rtn = attr;
4379 }
4380
4381 if (rtn == NULL)
4382 return (NULL);
4383
4384 if (rtn->attr_param_list)
4385 rtn->attr_avd = parser_list2avd(rtn->attr_param_list);
4386
4387 return (rtn);
4388 }
4389
4390 /*
4391 * Similar to get_attr, but converts the parameter string supplied with the
4392 * named attribute to an integer and stores the integer in the attr_avd
4393 * portion of the returned attr_t struct. If no parameter string is supplied
4394 * then it defaults to TRUE (1).
4395 */
4396 static attr_t *
get_attr_bool(cmd_t * cmd,int64_t name)4397 get_attr_bool(cmd_t *cmd, int64_t name)
4398 {
4399 attr_t *attr;
4400 attr_t *rtn = NULL;
4401
4402 for (attr = cmd->cmd_attr_list; attr != NULL;
4403 attr = attr->attr_next) {
4404 if (attr->attr_name == name)
4405 rtn = attr;
4406 }
4407
4408 if (rtn == NULL)
4409 return (NULL);
4410
4411 if (rtn->attr_param_list) {
4412 rtn->attr_avd = parser_list2avd(rtn->attr_param_list);
4413
4414 } else if (rtn->attr_avd == NULL) {
4415 rtn->attr_avd = avd_bool_alloc(TRUE);
4416 }
4417
4418 /* boolean attributes cannot point to random variables */
4419 if (AVD_IS_RANDOM(rtn->attr_avd)) {
4420 filebench_log(LOG_ERROR,
4421 "define flowop: Boolean attr %s cannot be random", name);
4422 filebench_shutdown(1);
4423 return (NULL);
4424 }
4425
4426 return (rtn);
4427 }
4428
4429 /*
4430 * removes the newly allocated local var from the shared local var
4431 * list, then puts it at the head of the private local var list
4432 * supplied as the second argument.
4433 */
4434 static void
add_lvar_to_list(var_t * newlvar,var_t ** lvar_list)4435 add_lvar_to_list(var_t *newlvar, var_t **lvar_list)
4436 {
4437 var_t *prev;
4438
4439 /* remove from shared local list, if there */
4440 if (newlvar == filebench_shm->shm_var_loc_list) {
4441 /* on top of list, just grap */
4442 filebench_shm->shm_var_loc_list = newlvar->var_next;
4443 } else {
4444 /* find newvar on list and remove */
4445 for (prev = filebench_shm->shm_var_loc_list; prev;
4446 prev = prev->var_next) {
4447 if (prev->var_next == newlvar)
4448 prev->var_next = newlvar->var_next;
4449 }
4450 }
4451 newlvar->var_next = NULL;
4452
4453 /* add to flowop private local list at head */
4454 newlvar->var_next = *lvar_list;
4455 *lvar_list = newlvar;
4456 }
4457
4458 /*
4459 * Searches the attribute list for the command for any allocated local
4460 * variables. The attribute list is created by the parser from the list of
4461 * attributes supplied with certain commands, such as the define and flowop
4462 * commands. Places all found local vars onto the flowop's local variable
4463 * list.
4464 */
4465 static void
get_attr_lvars(cmd_t * cmd,flowop_t * flowop)4466 get_attr_lvars(cmd_t *cmd, flowop_t *flowop)
4467 {
4468 attr_t *attr;
4469 var_t *list_tail, *orig_lvar_list;
4470
4471 /* save the local var list */
4472 orig_lvar_list = flowop->fo_lvar_list;
4473
4474 for (attr = cmd->cmd_attr_list; attr != NULL;
4475 attr = attr->attr_next) {
4476
4477 if (attr->attr_name == FSA_LVAR_ASSIGN) {
4478 var_t *newvar, *prev;
4479
4480 if ((newvar = (var_t *)attr->attr_avd) == NULL)
4481 continue;
4482
4483 add_lvar_to_list(newvar, &flowop->fo_lvar_list);
4484 var_update_comp_lvars(newvar, orig_lvar_list, NULL);
4485 }
4486 }
4487 }
4488
4489 /*
4490 * Allocates memory for a list_t structure, initializes it to zero, and
4491 * returns a pointer to it. On failure, returns NULL.
4492 */
4493 static list_t *
alloc_list()4494 alloc_list()
4495 {
4496 list_t *list;
4497
4498 if ((list = malloc(sizeof (list_t))) == NULL) {
4499 return (NULL);
4500 }
4501
4502 (void) memset(list, 0, sizeof (list_t));
4503 return (list);
4504 }
4505
4506
4507 #define USAGE1 \
4508 "Usage:\n" \
4509 "go_filebench: interpret f script and generate file workload\n" \
4510 "Options:\n" \
4511 " [-h] Display verbose help\n" \
4512 " [-p] Disable opening /proc to set uacct to enable truss\n"
4513
4514 #define PARSER_CMDS \
4515 "create [files|filesets|processes]\n" \
4516 "stats [clear|snap]\n" \
4517 "stats command \"shell command $var1,$var2...\"\n" \
4518 "stats directory <directory>\n" \
4519 "sleep <sleep-value>\n" \
4520 "quit\n\n" \
4521 "Variables:\n" \
4522 "set $var = value\n" \
4523 " $var - regular variables\n" \
4524 " ${var} - internal special variables\n" \
4525 " $(var) - environment variables\n\n"
4526
4527 #define PARSER_EXAMPLE \
4528 "Example:\n\n" \
4529 "#!" FILEBENCHDIR "/bin/go_filebench -f\n" \
4530 "\n" \
4531 "define file name=bigfile,path=bigfile,size=1g,prealloc,reuse\n" \
4532 "define process name=randomizer\n" \
4533 "{\n" \
4534 " thread random-thread procname=randomizer\n" \
4535 " {\n" \
4536 " flowop read name=random-read,filename=bigfile,iosize=16k,random\n" \
4537 " }\n" \
4538 "}\n" \
4539 "create files\n" \
4540 "create processes\n" \
4541 "stats clear\n" \
4542 "sleep 30\n" \
4543 "stats snap\n"
4544
4545 /*
4546 * usage() display brief or verbose help for the filebench(1) command.
4547 */
4548 static void
usage(int help)4549 usage(int help)
4550 {
4551 if (help >= 1)
4552 (void) fprintf(stderr, USAGE1, cmdname);
4553 if (help >= 2) {
4554
4555 (void) fprintf(stderr,
4556 "\n'f' language definition:\n\n");
4557 fileset_usage();
4558 procflow_usage();
4559 threadflow_usage();
4560 flowoplib_usage();
4561 eventgen_usage();
4562 (void) fprintf(stderr, PARSER_CMDS);
4563 (void) fprintf(stderr, PARSER_EXAMPLE);
4564 }
4565 exit(E_USAGE);
4566 }
4567
4568 int
yywrap()4569 yywrap()
4570 {
4571 char buf[1024];
4572
4573 if (parentscript) {
4574 yyin = parentscript;
4575 yy_switchfilescript(yyin);
4576 parentscript = NULL;
4577 return (0);
4578 } else
4579 return (1);
4580 }
4581