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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 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 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 * 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 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 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 }