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 #include <stdlib.h> 29 #include <stdio.h> 30 #include <string.h> 31 #include <errno.h> 32 33 #include "filebench.h" 34 #include "vars.h" 35 #include "misc.h" 36 #include "utils.h" 37 #include "stats.h" 38 #include "eventgen.h" 39 #include "fb_random.h" 40 41 static var_t *var_find_dynamic(char *name); 42 static boolean_t var_get_bool(var_t *var); 43 static fbint_t var_get_int(var_t *var); 44 static double var_get_dbl(var_t *var); 45 46 /* 47 * The filebench variables system has attribute value descriptors (avd_t) 48 * where an avd contains a boolean, integer, double, string, random 49 * distribution object ptr, boolean ptr, integer ptr, double ptr, 50 * string ptr, or variable ptr. The system also has the variables 51 * themselves, (var_t), which are named, typed entities which can be 52 * allocated, selected and changed using the "set" command and used in 53 * attribute assignments. The variables contain either a boolean, an 54 * integer, a double, a string or pointer to an associated random 55 * distribution object. Both avd_t and var_t entities are allocated 56 * from interprocess shared memory space. 57 * 58 * The attribute descriptors implement delayed binding to variable values, 59 * which is necessary because the values of variables may be changed 60 * between the time the workload file is loaded and it is actually run, 61 * either by further "set" commands in the file or from the command line 62 * interface. For random variables, they actually point to the random 63 * distribution object, allowing FileBench to invoke the appropriate 64 * random distribution function on each access to the attribute. However, 65 * for static attributes, the value is just loaded in the descriptor 66 * directly, avoiding the need to allocate a variable to hold the static 67 * value. 68 * 69 * The routines in this module are used to allocate, locate, and 70 * manipulate the attribute descriptors, and vars. Routines are 71 * also included to convert between the component strings, doubles 72 * and integers of vars, and said components of avd_t. 73 */ 74 75 76 /* 77 * returns a pointer to a string indicating the type of data contained 78 * in the supplied attribute variable descriptor. 79 */ 80 static char * 81 avd_get_type_string(avd_t avd) 82 { 83 switch (avd->avd_type) { 84 case AVD_INVALID: 85 return ("uninitialized"); 86 87 case AVD_VAL_BOOL: 88 return ("boolean value"); 89 90 case AVD_VARVAL_BOOL: 91 return ("points to boolean in var_t"); 92 93 case AVD_VAL_INT: 94 return ("integer value"); 95 96 case AVD_VARVAL_INT: 97 return ("points to integer in var_t"); 98 99 case AVD_VAL_STR: 100 return ("string"); 101 102 case AVD_VARVAL_STR: 103 return ("points to string in var_t"); 104 105 case AVD_VAL_DBL: 106 return ("double float value"); 107 108 case AVD_VARVAL_DBL: 109 return ("points to double float in var_t"); 110 111 case AVD_IND_VAR: 112 return ("points to a var_t"); 113 114 case AVD_IND_RANDVAR: 115 return ("points to var_t's random distribution object"); 116 117 default: 118 return ("illegal avd type"); 119 } 120 } 121 122 /* 123 * returns a pointer to a string indicating the type of data contained 124 * in the supplied variable. 125 */ 126 static char * 127 var_get_type_string(var_t *ivp) 128 { 129 switch (ivp->var_type & VAR_TYPE_SET_MASK) { 130 case VAR_TYPE_BOOL_SET: 131 return ("boolean"); 132 133 case VAR_TYPE_INT_SET: 134 return ("integer"); 135 136 case VAR_TYPE_STR_SET: 137 return ("string"); 138 139 case VAR_TYPE_DBL_SET: 140 return ("double float"); 141 142 case VAR_TYPE_RAND_SET: 143 return ("random"); 144 145 default: 146 return ("empty"); 147 } 148 } 149 150 /* 151 * Returns the fbint_t pointed to by the supplied avd_t "avd". 152 */ 153 fbint_t 154 avd_get_int(avd_t avd) 155 { 156 randdist_t *rndp; 157 158 if (avd == NULL) 159 return (0); 160 161 switch (avd->avd_type) { 162 case AVD_VAL_INT: 163 return (avd->avd_val.intval); 164 165 case AVD_VARVAL_INT: 166 if (avd->avd_val.intptr) 167 return (*(avd->avd_val.intptr)); 168 else 169 return (0); 170 171 case AVD_IND_VAR: 172 return (var_get_int(avd->avd_val.varptr)); 173 174 case AVD_IND_RANDVAR: 175 if ((rndp = avd->avd_val.randptr) == NULL) 176 return (0); 177 else 178 return ((fbint_t)rndp->rnd_get(rndp)); 179 180 default: 181 filebench_log(LOG_ERROR, 182 "Attempt to get integer from %s avd", 183 avd_get_type_string(avd)); 184 return (0); 185 } 186 } 187 188 /* 189 * Returns the floating point value of a variable pointed to by the 190 * supplied avd_t "avd". Intended to get the actual (double) value 191 * supplied by the random variable. 192 */ 193 double 194 avd_get_dbl(avd_t avd) 195 { 196 randdist_t *rndp; 197 198 if (avd == NULL) 199 return (0.0); 200 201 switch (avd->avd_type) { 202 case AVD_VAL_INT: 203 return ((double)avd->avd_val.intval); 204 205 case AVD_VAL_DBL: 206 return (avd->avd_val.dblval); 207 208 case AVD_VARVAL_INT: 209 if (avd->avd_val.intptr) 210 return ((double)(*(avd->avd_val.intptr))); 211 else 212 return (0.0); 213 214 case AVD_VARVAL_DBL: 215 if (avd->avd_val.dblptr) 216 return (*(avd->avd_val.dblptr)); 217 else 218 return (0.0); 219 220 case AVD_IND_VAR: 221 return (var_get_dbl(avd->avd_val.varptr)); 222 223 case AVD_IND_RANDVAR: 224 if ((rndp = avd->avd_val.randptr) == NULL) { 225 return (0.0); 226 } else 227 return (rndp->rnd_get(rndp)); 228 229 default: 230 filebench_log(LOG_ERROR, 231 "Attempt to get floating point from %s avd", 232 avd_get_type_string(avd)); 233 return (0.0); 234 } 235 } 236 237 /* 238 * Returns the boolean pointed to by the supplied avd_t "avd". 239 */ 240 boolean_t 241 avd_get_bool(avd_t avd) 242 { 243 if (avd == NULL) 244 return (0); 245 246 switch (avd->avd_type) { 247 case AVD_VAL_BOOL: 248 return (avd->avd_val.boolval); 249 250 case AVD_VARVAL_BOOL: 251 if (avd->avd_val.boolptr) 252 return (*(avd->avd_val.boolptr)); 253 else 254 return (FALSE); 255 256 /* for backwards compatibility with old workloads */ 257 case AVD_VAL_INT: 258 if (avd->avd_val.intval != 0) 259 return (TRUE); 260 else 261 return (FALSE); 262 263 case AVD_VARVAL_INT: 264 if (avd->avd_val.intptr) 265 if (*(avd->avd_val.intptr) != 0) 266 return (TRUE); 267 268 return (FALSE); 269 270 case AVD_IND_VAR: 271 return (var_get_bool(avd->avd_val.varptr)); 272 273 default: 274 filebench_log(LOG_ERROR, 275 "Attempt to get boolean from %s avd", 276 avd_get_type_string(avd)); 277 return (FALSE); 278 } 279 } 280 281 /* 282 * Returns the string pointed to by the supplied avd_t "avd". 283 */ 284 char * 285 avd_get_str(avd_t avd) 286 { 287 var_t *ivp; 288 289 if (avd == NULL) 290 return (NULL); 291 292 switch (avd->avd_type) { 293 case AVD_VAL_STR: 294 return (avd->avd_val.strval); 295 296 case AVD_VARVAL_STR: 297 if (avd->avd_val.strptr) 298 return (*avd->avd_val.strptr); 299 else 300 return (NULL); 301 302 case AVD_IND_VAR: 303 ivp = avd->avd_val.varptr; 304 305 if (ivp && VAR_HAS_STRING(ivp)) 306 return (ivp->var_val.string); 307 308 filebench_log(LOG_ERROR, 309 "Attempt to get string from %s var $%s", 310 var_get_type_string(ivp), ivp->var_name); 311 return (NULL); 312 313 default: 314 filebench_log(LOG_ERROR, 315 "Attempt to get string from %s avd", 316 avd_get_type_string(avd)); 317 return (NULL); 318 } 319 } 320 321 /* 322 * Allocates a avd_t from ipc memory space. 323 * logs an error and returns NULL on failure. 324 */ 325 static avd_t 326 avd_alloc_cmn(void) 327 { 328 avd_t rtn; 329 330 if ((rtn = (avd_t)ipc_malloc(FILEBENCH_AVD)) == NULL) 331 filebench_log(LOG_ERROR, "Avd alloc failed"); 332 333 return (rtn); 334 } 335 336 /* 337 * pre-loads the allocated avd_t with the boolean_t "bool". 338 * Returns the avd_t on success, NULL on failure. 339 */ 340 avd_t 341 avd_bool_alloc(boolean_t bool) 342 { 343 avd_t avd; 344 345 if ((avd = avd_alloc_cmn()) == NULL) 346 return (NULL); 347 348 avd->avd_type = AVD_VAL_BOOL; 349 avd->avd_val.boolval = bool; 350 351 filebench_log(LOG_DEBUG_IMPL, "Alloc boolean %d", bool); 352 353 return (avd); 354 } 355 356 /* 357 * pre-loads the allocated avd_t with the fbint_t "integer". 358 * Returns the avd_t on success, NULL on failure. 359 */ 360 avd_t 361 avd_int_alloc(fbint_t integer) 362 { 363 avd_t avd; 364 365 if ((avd = avd_alloc_cmn()) == NULL) 366 return (NULL); 367 368 avd->avd_type = AVD_VAL_INT; 369 avd->avd_val.intval = integer; 370 371 filebench_log(LOG_DEBUG_IMPL, "Alloc integer %llu", 372 (u_longlong_t)integer); 373 374 return (avd); 375 } 376 377 /* 378 * Gets a avd_t and points it to the var that 379 * it will eventually be filled from 380 */ 381 static avd_t 382 avd_alloc_var_ptr(var_t *var) 383 { 384 avd_t avd; 385 386 if (var == NULL) 387 return (NULL); 388 389 if ((avd = avd_alloc_cmn()) == NULL) 390 return (NULL); 391 392 switch (var->var_type & VAR_TYPE_SET_MASK) { 393 case VAR_TYPE_BOOL_SET: 394 avd->avd_type = AVD_VARVAL_BOOL; 395 avd->avd_val.boolptr = (&var->var_val.boolean); 396 break; 397 398 case VAR_TYPE_INT_SET: 399 avd->avd_type = AVD_VARVAL_INT; 400 avd->avd_val.intptr = (&var->var_val.integer); 401 break; 402 403 case VAR_TYPE_STR_SET: 404 avd->avd_type = AVD_VARVAL_STR; 405 avd->avd_val.strptr = &(var->var_val.string); 406 break; 407 408 case VAR_TYPE_DBL_SET: 409 avd->avd_type = AVD_VARVAL_DBL; 410 avd->avd_val.dblptr = &(var->var_val.dbl_flt); 411 break; 412 413 case VAR_TYPE_RAND_SET: 414 avd->avd_type = AVD_IND_RANDVAR; 415 avd->avd_val.randptr = var->var_val.randptr; 416 break; 417 418 case VAR_TYPE_INDVAR_SET: 419 avd->avd_type = AVD_IND_VAR; 420 if ((var->var_type & VAR_INDVAR_MASK) == VAR_IND_ASSIGN) 421 avd->avd_val.varptr = var->var_varptr1; 422 else 423 avd->avd_val.varptr = var; 424 425 break; 426 427 default: 428 avd->avd_type = AVD_IND_VAR; 429 avd->avd_val.varptr = var; 430 break; 431 } 432 return (avd); 433 } 434 435 /* 436 * Gets a avd_t, then allocates and initializes a piece of 437 * shared string memory, putting the pointer to it into the just 438 * allocated string pointer location. The routine returns a pointer 439 * to the string pointer location or returns NULL on error. 440 */ 441 avd_t 442 avd_str_alloc(char *string) 443 { 444 avd_t avd; 445 446 if (string == NULL) { 447 filebench_log(LOG_ERROR, "No string supplied\n"); 448 return (NULL); 449 } 450 451 if ((avd = avd_alloc_cmn()) == NULL) 452 return (NULL); 453 454 avd->avd_type = AVD_VAL_STR; 455 avd->avd_val.strval = ipc_stralloc(string); 456 457 filebench_log(LOG_DEBUG_IMPL, 458 "Alloc string %s ptr %zx", 459 string, avd); 460 461 return (avd); 462 } 463 464 /* 465 * Allocates a var (var_t) from interprocess shared memory. 466 * Places the allocated var on the end of the globally shared 467 * shm_var_list. Finally, the routine allocates a string containing 468 * a copy of the supplied "name" string. If any allocations 469 * fails, returns NULL, otherwise it returns a pointer to the 470 * newly allocated var. 471 */ 472 static var_t * 473 var_alloc_cmn(char *name, int var_type) 474 { 475 var_t **var_listp; 476 var_t *var = NULL; 477 var_t *prev = NULL; 478 var_t *newvar; 479 480 if ((newvar = (var_t *)ipc_malloc(FILEBENCH_VARIABLE)) == NULL) { 481 filebench_log(LOG_ERROR, "Out of memory for variables"); 482 return (NULL); 483 } 484 (void) memset(newvar, 0, sizeof (newvar)); 485 newvar->var_type = var_type; 486 487 if ((newvar->var_name = ipc_stralloc(name)) == NULL) { 488 filebench_log(LOG_ERROR, "Out of memory for variables"); 489 return (NULL); 490 } 491 492 switch (var_type & VAR_TYPE_MASK) { 493 case VAR_TYPE_RANDOM: 494 case VAR_TYPE_GLOBAL: 495 var_listp = &filebench_shm->shm_var_list; 496 break; 497 498 case VAR_TYPE_DYNAMIC: 499 var_listp = &filebench_shm->shm_var_dyn_list; 500 break; 501 502 case VAR_TYPE_LOCAL: 503 /* place on head of shared local list */ 504 newvar->var_next = filebench_shm->shm_var_loc_list; 505 filebench_shm->shm_var_loc_list = newvar; 506 return (newvar); 507 508 default: 509 var_listp = &filebench_shm->shm_var_list; 510 break; 511 } 512 513 /* add to the end of list */ 514 for (var = *var_listp; var != NULL; var = var->var_next) 515 prev = var; /* Find end of list */ 516 if (prev != NULL) 517 prev->var_next = newvar; 518 else 519 *var_listp = newvar; 520 521 return (newvar); 522 } 523 524 /* 525 * Allocates a var (var_t) from interprocess shared memory after 526 * first adjusting the name to elminate the leading $. Places the 527 * allocated var temporarily on the end of the globally 528 * shared var_loc_list. If the allocation fails, returns NULL, 529 * otherwise it returns a pointer to the newly allocated var. 530 */ 531 var_t * 532 var_lvar_alloc_local(char *name) 533 { 534 if (name[0] == '$') 535 name += 1; 536 537 return (var_alloc_cmn(name, VAR_TYPE_LOCAL)); 538 } 539 540 /* 541 * Allocates a var (var_t) from interprocess shared memory and 542 * places the allocated var on the end of the globally shared 543 * shm_var_list. If the allocation fails, returns NULL, otherwise 544 * it returns a pointer to the newly allocated var. 545 */ 546 static var_t * 547 var_alloc(char *name) 548 { 549 return (var_alloc_cmn(name, VAR_TYPE_GLOBAL)); 550 } 551 552 /* 553 * Allocates a var (var_t) from interprocess shared memory. 554 * Places the allocated var on the end of the globally shared 555 * shm_var_dyn_list. If the allocation fails, returns NULL, otherwise 556 * it returns a pointer to the newly allocated var. 557 */ 558 static var_t * 559 var_alloc_dynamic(char *name) 560 { 561 return (var_alloc_cmn(name, VAR_TYPE_DYNAMIC)); 562 } 563 564 /* 565 * Searches for var_t with name "name" in the shm_var_loc_list, 566 * then, if not found, in the global shm_var_list. If a matching 567 * local or global var is found, returns a pointer to the var_t, 568 * otherwise returns NULL. 569 */ 570 static var_t * 571 var_find(char *name) 572 { 573 var_t *var; 574 575 for (var = filebench_shm->shm_var_loc_list; var != NULL; 576 var = var->var_next) { 577 if (strcmp(var->var_name, name) == 0) 578 return (var); 579 } 580 581 for (var = filebench_shm->shm_var_list; var != NULL; 582 var = var->var_next) { 583 if (strcmp(var->var_name, name) == 0) 584 return (var); 585 } 586 587 return (NULL); 588 } 589 590 /* 591 * Searches for var_t with name "name" in the supplied shm_var_list. 592 * If not found there, checks the global list. If still 593 * unsuccessful, returns NULL. Otherwise returns a pointer to the var_t. 594 */ 595 static var_t * 596 var_find_list_only(char *name, var_t *var_list) 597 { 598 var_t *var; 599 600 for (var = var_list; var != NULL; var = var->var_next) { 601 if (strcmp(var->var_name, name) == 0) 602 return (var); 603 } 604 605 return (NULL); 606 } 607 608 /* 609 * Searches for var_t with name "name" in the supplied shm_var_list. 610 * If not found there, checks the global list. If still 611 * unsuccessful, returns NULL. Otherwise returns a pointer to the var_t. 612 */ 613 static var_t * 614 var_find_list(char *name, var_t *var_list) 615 { 616 var_t *var; 617 618 if ((var = var_find_list_only(name, var_list)) != NULL) 619 return (var); 620 else 621 return (var_find(name)); 622 } 623 624 /* 625 * Searches for the named var and returns it if found. If not 626 * found it allocates a new variable 627 */ 628 static var_t * 629 var_find_alloc(char *name) 630 { 631 var_t *var; 632 633 if (name == NULL) { 634 filebench_log(LOG_ERROR, 635 "var_find_alloc: Var name not supplied"); 636 return (NULL); 637 } 638 639 name += 1; 640 641 if ((var = var_find(name)) == NULL) { 642 var = var_alloc(name); 643 } 644 return (var); 645 } 646 647 /* 648 * Searches for the named var, and, if found, sets its 649 * var_val.boolean's value to that of the supplied boolean. 650 * If not found, the routine allocates a new var and sets 651 * its var_val.boolean's value to that of the supplied 652 * boolean. If the named var cannot be found or allocated 653 * the routine returns -1, otherwise it returns 0. 654 */ 655 int 656 var_assign_boolean(char *name, boolean_t bool) 657 { 658 var_t *var; 659 660 if ((var = var_find_alloc(name)) == NULL) { 661 filebench_log(LOG_ERROR, "Cannot assign variable %s", 662 name); 663 return (-1); 664 } 665 666 if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { 667 filebench_log(LOG_ERROR, 668 "Cannot assign integer to random variable %s", name); 669 return (-1); 670 } 671 672 VAR_SET_BOOL(var, bool); 673 674 filebench_log(LOG_DEBUG_SCRIPT, "Assign boolean %s=%d", 675 name, bool); 676 677 return (0); 678 } 679 680 /* 681 * Searches for the named var, and, if found, sets its 682 * var_integer's value to that of the supplied integer. 683 * If not found, the routine allocates a new var and sets 684 * its var_integers's value to that of the supplied 685 * integer. If the named var cannot be found or allocated 686 * the routine returns -1, otherwise it returns 0. 687 */ 688 int 689 var_assign_integer(char *name, fbint_t integer) 690 { 691 var_t *var; 692 693 if ((var = var_find_alloc(name)) == NULL) { 694 filebench_log(LOG_ERROR, "Cannot assign variable %s", 695 name); 696 return (-1); 697 } 698 699 if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { 700 filebench_log(LOG_ERROR, 701 "Cannot assign integer to random variable %s", name); 702 return (-1); 703 } 704 705 VAR_SET_INT(var, integer); 706 707 filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%llu", 708 name, (u_longlong_t)integer); 709 710 return (0); 711 } 712 713 /* 714 * Add, subtract, multiply or divide two integers based on optype 715 * passed from caller. 716 */ 717 static fbint_t 718 var_binary_integer_op(var_t *var) 719 { 720 fbint_t result; 721 fbint_t src1, src2; 722 723 if (var == NULL) 724 return (0); 725 726 switch (var->var_type & VAR_INDBINOP_MASK) { 727 case VAR_IND_BINOP_INT: 728 src2 = var->var_val.integer; 729 break; 730 731 case VAR_IND_BINOP_DBL: 732 src2 = (fbint_t)var->var_val.dbl_flt; 733 break; 734 735 case VAR_IND_BINOP_VAR: 736 if (var->var_val.varptr2 != NULL) 737 src2 = var_get_int(var->var_val.varptr2); 738 else 739 src2 = 0; 740 break; 741 } 742 743 if (var->var_varptr1 != NULL) 744 src1 = var_get_int(var->var_varptr1); 745 else 746 src1 = 0; 747 748 switch (var->var_type & VAR_INDVAR_MASK) { 749 case VAR_IND_VAR_SUM_VC: 750 result = src1 + src2; 751 break; 752 753 case VAR_IND_VAR_DIF_VC: 754 result = src1 - src2; 755 break; 756 757 case VAR_IND_C_DIF_VAR: 758 result = src2 - src1; 759 break; 760 761 case VAR_IND_VAR_MUL_VC: 762 result = src1 * src2; 763 break; 764 765 case VAR_IND_VAR_DIV_VC: 766 result = src1 / src2; 767 break; 768 769 case VAR_IND_C_DIV_VAR: 770 result = src2 / src1; 771 break; 772 773 default: 774 filebench_log(LOG_DEBUG_IMPL, 775 "var_binary_integer_op: Called with unknown IND_TYPE"); 776 result = 0; 777 break; 778 } 779 return (result); 780 } 781 782 /* 783 * Add, subtract, multiply or divide two double precision floating point 784 * numbers based on optype passed from caller. 785 */ 786 static double 787 var_binary_dbl_flt_op(var_t *var) 788 { 789 double result; 790 double src1, src2; 791 792 if (var == NULL) 793 return (0.0); 794 795 switch (var->var_type & VAR_INDBINOP_MASK) { 796 case VAR_IND_BINOP_INT: 797 src2 = (double)var->var_val.integer; 798 break; 799 800 case VAR_IND_BINOP_DBL: 801 src2 = var->var_val.dbl_flt; 802 break; 803 804 case VAR_IND_BINOP_VAR: 805 if (var->var_val.varptr2 != NULL) 806 src2 = var_get_dbl(var->var_val.varptr2); 807 else 808 src2 = 0; 809 break; 810 } 811 812 if (var->var_varptr1 != NULL) 813 src1 = var_get_dbl(var->var_varptr1); 814 else 815 src1 = 0; 816 817 switch (var->var_type & VAR_INDVAR_MASK) { 818 case VAR_IND_VAR_SUM_VC: 819 result = src1 + src2; 820 break; 821 822 case VAR_IND_VAR_DIF_VC: 823 result = src1 - src2; 824 break; 825 826 case VAR_IND_C_DIF_VAR: 827 result = src2 - src1; 828 break; 829 830 case VAR_IND_VAR_MUL_VC: 831 result = src1 * src2; 832 break; 833 834 case VAR_IND_C_DIV_VAR: 835 result = src2 / src1; 836 break; 837 838 case VAR_IND_VAR_DIV_VC: 839 result = src1 / src2; 840 break; 841 842 default: 843 filebench_log(LOG_DEBUG_IMPL, 844 "var_binary_dbl_flt_op: Called with unknown IND_TYPE"); 845 result = 0; 846 break; 847 } 848 return (result); 849 } 850 851 /* 852 * Perform a binary operation on a variable and an integer 853 */ 854 int 855 var_assign_op_var_int(char *name, int optype, char *src1, fbint_t src2) 856 { 857 var_t *var; 858 var_t *var_src1; 859 860 if ((var_src1 = var_find(src1+1)) == NULL) 861 return (FILEBENCH_ERROR); 862 863 if ((var = var_find_alloc(name)) == NULL) 864 return (FILEBENCH_ERROR); 865 866 if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { 867 filebench_log(LOG_ERROR, 868 "Cannot assign integer to random variable %s", name); 869 return (FILEBENCH_ERROR); 870 } 871 872 VAR_SET_BINOP_INDVAR(var, var_src1, optype); 873 874 var->var_val.integer = src2; 875 876 return (FILEBENCH_OK); 877 } 878 879 int 880 var_assign_op_var_var(char *name, int optype, char *src1, char *src2) 881 { 882 var_t *var; 883 var_t *var_src1; 884 var_t *var_src2; 885 886 if ((var_src1 = var_find(src1+1)) == NULL) 887 return (FILEBENCH_ERROR); 888 889 if ((var_src2 = var_find(src2+1)) == NULL) 890 return (FILEBENCH_ERROR); 891 892 if ((var = var_find_alloc(name)) == NULL) 893 return (FILEBENCH_ERROR); 894 895 if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { 896 filebench_log(LOG_ERROR, 897 "Cannot assign integer to random variable %s", name); 898 return (FILEBENCH_ERROR); 899 } 900 901 VAR_SET_BINOP_INDVAR(var, var_src1, optype); 902 903 var->var_val.varptr2 = var_src2; 904 905 return (FILEBENCH_OK); 906 } 907 908 /* 909 * Find a variable, and set it to random type. 910 * If it does not have a random extension, allocate one 911 */ 912 var_t * 913 var_find_randvar(char *name) 914 { 915 var_t *newvar; 916 917 name += 1; 918 919 if ((newvar = var_find(name)) == NULL) { 920 filebench_log(LOG_ERROR, 921 "failed to locate random variable $%s\n", name); 922 return (NULL); 923 } 924 925 /* set randdist pointer unless it is already set */ 926 if (((newvar->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) || 927 !VAR_HAS_RANDDIST(newvar)) { 928 filebench_log(LOG_ERROR, 929 "Found variable $%s not random\n", name); 930 return (NULL); 931 } 932 933 return (newvar); 934 } 935 936 /* 937 * Allocate a variable, and set it to random type. Then 938 * allocate a random extension. 939 */ 940 var_t * 941 var_define_randvar(char *name) 942 { 943 var_t *newvar; 944 randdist_t *rndp = NULL; 945 946 name += 1; 947 948 /* make sure variable doesn't already exist */ 949 if (var_find(name) != NULL) { 950 filebench_log(LOG_ERROR, 951 "variable name already in use\n"); 952 return (NULL); 953 } 954 955 /* allocate a random variable */ 956 if ((newvar = var_alloc_cmn(name, VAR_TYPE_RANDOM)) == NULL) { 957 filebench_log(LOG_ERROR, 958 "failed to alloc random variable\n"); 959 return (NULL); 960 } 961 962 /* set randdist pointer */ 963 if ((rndp = randdist_alloc()) == NULL) { 964 filebench_log(LOG_ERROR, 965 "failed to alloc random distribution object\n"); 966 return (NULL); 967 } 968 969 rndp->rnd_var = newvar; 970 VAR_SET_RAND(newvar, rndp); 971 972 return (newvar); 973 } 974 975 /* 976 * Searches for the named var, and if found returns an avd_t 977 * pointing to the var's var_integer, var_string or var_double 978 * as appropriate. If not found, attempts to allocate 979 * a var named "name" and returns an avd_t to it with 980 * no value set. If the var cannot be found or allocated, an 981 * error is logged and the run is terminated. 982 */ 983 avd_t 984 var_ref_attr(char *name) 985 { 986 var_t *var; 987 988 name += 1; 989 990 if ((var = var_find(name)) == NULL) 991 var = var_find_dynamic(name); 992 993 if (var == NULL) 994 var = var_alloc(name); 995 996 if (var == NULL) { 997 filebench_log(LOG_ERROR, "Invalid variable $%s", 998 name); 999 filebench_shutdown(1); 1000 } 1001 1002 /* allocate pointer to var and return */ 1003 return (avd_alloc_var_ptr(var)); 1004 } 1005 1006 /* 1007 * Converts the contents of a var to a string 1008 */ 1009 static char * 1010 var_get_string(var_t *var) 1011 { 1012 1013 if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { 1014 switch (var->var_val.randptr->rnd_type & RAND_TYPE_MASK) { 1015 case RAND_TYPE_UNIFORM: 1016 return (fb_stralloc("uniform random var")); 1017 case RAND_TYPE_GAMMA: 1018 return (fb_stralloc("gamma random var")); 1019 case RAND_TYPE_TABLE: 1020 return (fb_stralloc("tabular random var")); 1021 default: 1022 return (fb_stralloc("unitialized random var")); 1023 } 1024 } 1025 1026 if (VAR_HAS_STRING(var) && var->var_val.string) 1027 return (fb_stralloc(var->var_val.string)); 1028 1029 if (VAR_HAS_BOOLEAN(var)) { 1030 if (var->var_val.boolean) 1031 return (fb_stralloc("true")); 1032 else 1033 return (fb_stralloc("false")); 1034 } 1035 1036 if (VAR_HAS_INTEGER(var)) { 1037 char tmp[128]; 1038 1039 (void) snprintf(tmp, sizeof (tmp), "%llu", 1040 (u_longlong_t)var->var_val.integer); 1041 return (fb_stralloc(tmp)); 1042 } 1043 1044 if (VAR_HAS_INDVAR(var)) { 1045 var_t *ivp; 1046 1047 if ((ivp = var->var_varptr1) != NULL) { 1048 return (var_get_string(ivp)); 1049 } 1050 } 1051 1052 if (VAR_HAS_BINOP(var)) { 1053 char tmp[128]; 1054 1055 (void) snprintf(tmp, sizeof (tmp), "%llu", 1056 var_binary_integer_op(var)); 1057 return (fb_stralloc(tmp)); 1058 } 1059 1060 return (fb_stralloc("No default")); 1061 } 1062 1063 /* 1064 * Searches for the named var, and if found copies the var_val.string, 1065 * if it exists, a decimal number string representation of 1066 * var_val.integer, the state of var_val.boolean, or the type of random 1067 * distribution employed, into a malloc'd bit of memory using fb_stralloc(). 1068 * Returns a pointer to the created string, or NULL on failure. 1069 */ 1070 char * 1071 var_to_string(char *name) 1072 { 1073 var_t *var; 1074 1075 name += 1; 1076 1077 if ((var = var_find(name)) == NULL) 1078 var = var_find_dynamic(name); 1079 1080 if (var == NULL) 1081 return (NULL); 1082 1083 return (var_get_string(var)); 1084 } 1085 1086 /* 1087 * Returns the boolean from the supplied var_t "var". 1088 */ 1089 static boolean_t 1090 var_get_bool(var_t *var) 1091 { 1092 if (var == NULL) 1093 return (0); 1094 1095 if (VAR_HAS_BOOLEAN(var)) 1096 return (var->var_val.boolean); 1097 1098 if (VAR_HAS_INTEGER(var)) { 1099 if (var->var_val.integer == 0) 1100 return (FALSE); 1101 else 1102 return (TRUE); 1103 } 1104 1105 filebench_log(LOG_ERROR, 1106 "Attempt to get boolean from %s var $%s", 1107 var_get_type_string(var), var->var_name); 1108 return (FALSE); 1109 } 1110 1111 /* 1112 * Returns the fbint_t from the supplied var_t "var". 1113 */ 1114 static fbint_t 1115 var_get_int(var_t *var) 1116 { 1117 randdist_t *rndp; 1118 1119 if (var == NULL) 1120 return (0); 1121 1122 if (VAR_HAS_INTEGER(var)) 1123 return (var->var_val.integer); 1124 1125 if (VAR_HAS_RANDDIST(var)) { 1126 if ((rndp = var->var_val.randptr) != NULL) 1127 return ((fbint_t)rndp->rnd_get(rndp)); 1128 } 1129 1130 if (VAR_HAS_BINOP(var)) 1131 return (var_binary_integer_op(var)); 1132 1133 filebench_log(LOG_ERROR, 1134 "Attempt to get integer from %s var $%s", 1135 var_get_type_string(var), var->var_name); 1136 return (0); 1137 } 1138 1139 /* 1140 * Returns the floating point value of a variable pointed to by the 1141 * supplied var_t "var". Intended to get the actual (double) value 1142 * supplied by the random variable. 1143 */ 1144 static double 1145 var_get_dbl(var_t *var) 1146 { 1147 randdist_t *rndp; 1148 1149 if (var == NULL) 1150 return (0.0); 1151 1152 if (VAR_HAS_INTEGER(var)) 1153 return ((double)var->var_val.integer); 1154 1155 if (VAR_HAS_DOUBLE(var)) 1156 return (var->var_val.dbl_flt); 1157 1158 if (VAR_HAS_RANDDIST(var)) { 1159 if ((rndp = var->var_val.randptr) != NULL) 1160 return (rndp->rnd_get(rndp)); 1161 } 1162 1163 if (VAR_HAS_BINOP(var)) 1164 return (var_binary_dbl_flt_op(var)); 1165 1166 filebench_log(LOG_ERROR, 1167 "Attempt to get double float from %s var $%s", 1168 var_get_type_string(var), var->var_name); 1169 return (0.0); 1170 } 1171 1172 /* 1173 * Searches for the named var, and if found returns the value, 1174 * of var_val.boolean. If the var is not found, or a boolean 1175 * value has not been set, logs an error and returns 0. 1176 */ 1177 boolean_t 1178 var_to_boolean(char *name) 1179 { 1180 var_t *var; 1181 1182 name += 1; 1183 1184 if ((var = var_find(name)) == NULL) 1185 var = var_find_dynamic(name); 1186 1187 if (var != NULL) 1188 return (var_get_bool(var)); 1189 1190 filebench_log(LOG_ERROR, 1191 "Variable %s referenced before set", name); 1192 1193 return (FALSE); 1194 } 1195 1196 /* 1197 * Searches for the named var, and if found returns the value, 1198 * of var_val.integer. If the var is not found, or the an 1199 * integer value has not been set, logs an error and returns 0. 1200 */ 1201 fbint_t 1202 var_to_integer(char *name) 1203 { 1204 var_t *var; 1205 1206 name += 1; 1207 1208 if ((var = var_find(name)) == NULL) 1209 var = var_find_dynamic(name); 1210 1211 if (var != NULL) 1212 return (var_get_int(var)); 1213 1214 filebench_log(LOG_ERROR, 1215 "Variable %s referenced before set", name); 1216 1217 return (0); 1218 } 1219 1220 /* 1221 * Searches for the named var, and if found returns the value, 1222 * of var_val.dbl_flt. If the var is not found, or the 1223 * floating value has not been set, logs an error and returns 0.0. 1224 */ 1225 double 1226 var_to_double(char *name) 1227 { 1228 var_t *var; 1229 1230 name += 1; 1231 1232 if ((var = var_find(name)) == NULL) 1233 var = var_find_dynamic(name); 1234 1235 if (var != NULL) 1236 return (var_get_dbl(var)); 1237 1238 filebench_log(LOG_ERROR, 1239 "Variable %s referenced before set", name); 1240 1241 return (0.0); 1242 } 1243 1244 /* 1245 * Searches for the named random var, and if found, converts the 1246 * requested parameter into a string or a decimal number string 1247 * representation, into a malloc'd bit of memory using fb_stralloc(). 1248 * Returns a pointer to the created string, or calls var_to_string() 1249 * if a random variable isn't found. 1250 */ 1251 char * 1252 var_randvar_to_string(char *name, int param_name) 1253 { 1254 var_t *var; 1255 fbint_t value; 1256 1257 if ((var = var_find(name + 1)) == NULL) 1258 return (var_to_string(name)); 1259 1260 if (((var->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) || 1261 !VAR_HAS_RANDDIST(var)) 1262 return (var_to_string(name)); 1263 1264 switch (param_name) { 1265 case RAND_PARAM_TYPE: 1266 switch (var->var_val.randptr->rnd_type & RAND_TYPE_MASK) { 1267 case RAND_TYPE_UNIFORM: 1268 return (fb_stralloc("uniform")); 1269 case RAND_TYPE_GAMMA: 1270 return (fb_stralloc("gamma")); 1271 case RAND_TYPE_TABLE: 1272 return (fb_stralloc("tabular")); 1273 default: 1274 return (fb_stralloc("uninitialized")); 1275 } 1276 1277 case RAND_PARAM_SRC: 1278 if (var->var_val.randptr->rnd_type & RAND_SRC_GENERATOR) 1279 return (fb_stralloc("rand48")); 1280 else 1281 return (fb_stralloc("urandom")); 1282 1283 case RAND_PARAM_SEED: 1284 value = avd_get_int(var->var_val.randptr->rnd_seed); 1285 break; 1286 1287 case RAND_PARAM_MIN: 1288 value = avd_get_int(var->var_val.randptr->rnd_min); 1289 break; 1290 1291 case RAND_PARAM_MEAN: 1292 value = avd_get_int(var->var_val.randptr->rnd_mean); 1293 break; 1294 1295 case RAND_PARAM_GAMMA: 1296 value = avd_get_int(var->var_val.randptr->rnd_gamma); 1297 break; 1298 1299 case RAND_PARAM_ROUND: 1300 value = avd_get_int(var->var_val.randptr->rnd_round); 1301 break; 1302 1303 default: 1304 return (NULL); 1305 1306 } 1307 1308 /* just an integer value if we got here */ 1309 { 1310 char tmp[128]; 1311 1312 (void) snprintf(tmp, sizeof (tmp), "%llu", 1313 (u_longlong_t)value); 1314 return (fb_stralloc(tmp)); 1315 } 1316 } 1317 1318 /* 1319 * Copies the value stored in the source string into the destination 1320 * string. Returns -1 if any problems encountered, 0 otherwise. 1321 */ 1322 static int 1323 var_copy(var_t *dst_var, var_t *src_var) { 1324 1325 if (VAR_HAS_BOOLEAN(src_var)) { 1326 VAR_SET_BOOL(dst_var, src_var->var_val.boolean); 1327 filebench_log(LOG_DEBUG_SCRIPT, 1328 "Assign var %s=%s", dst_var->var_name, 1329 dst_var->var_val.boolean?"true":"false"); 1330 } 1331 1332 if (VAR_HAS_INTEGER(src_var)) { 1333 VAR_SET_INT(dst_var, src_var->var_val.integer); 1334 filebench_log(LOG_DEBUG_SCRIPT, 1335 "Assign var %s=%llu", dst_var->var_name, 1336 (u_longlong_t)dst_var->var_val.integer); 1337 } 1338 1339 if (VAR_HAS_DOUBLE(src_var)) { 1340 VAR_SET_DBL(dst_var, src_var->var_val.dbl_flt); 1341 filebench_log(LOG_DEBUG_SCRIPT, 1342 "Assign var %s=%lf", dst_var->var_name, 1343 dst_var->var_val.dbl_flt); 1344 } 1345 1346 if (VAR_HAS_STRING(src_var)) { 1347 char *strptr; 1348 1349 if ((strptr = 1350 ipc_stralloc(src_var->var_val.string)) == NULL) { 1351 filebench_log(LOG_ERROR, 1352 "Cannot assign string for variable %s", 1353 dst_var->var_name); 1354 return (-1); 1355 } 1356 VAR_SET_STR(dst_var, strptr); 1357 filebench_log(LOG_DEBUG_SCRIPT, 1358 "Assign var %s=%s", dst_var->var_name, 1359 dst_var->var_val.string); 1360 } 1361 1362 if (VAR_HAS_INDVAR(src_var)) { 1363 VAR_SET_INDVAR(dst_var, src_var->var_varptr1); 1364 filebench_log(LOG_DEBUG_SCRIPT, 1365 "Assign var %s to var %s", dst_var->var_name, 1366 src_var->var_name); 1367 } 1368 return (0); 1369 } 1370 1371 /* 1372 * Searches for the var named "name", and if not found 1373 * allocates it. The then copies the value from 1374 * the src_var into the destination var "name" 1375 * If the var "name" cannot be found or allocated, or the var "src_name" 1376 * cannot be found, the routine returns -1, otherwise it returns 0. 1377 */ 1378 int 1379 var_assign_var(char *name, char *src_name) 1380 { 1381 var_t *dst_var, *src_var; 1382 1383 name += 1; 1384 src_name += 1; 1385 1386 if ((src_var = var_find(src_name)) == NULL) { 1387 filebench_log(LOG_ERROR, 1388 "Cannot find source variable %s", src_name); 1389 return (-1); 1390 } 1391 1392 if ((dst_var = var_find(name)) == NULL) 1393 dst_var = var_alloc(name); 1394 1395 if (dst_var == NULL) { 1396 filebench_log(LOG_ERROR, "Cannot assign variable %s", 1397 name); 1398 return (-1); 1399 } 1400 1401 if ((dst_var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { 1402 filebench_log(LOG_ERROR, 1403 "Cannot assign var to Random variable %s", name); 1404 return (-1); 1405 } 1406 1407 return (var_copy(dst_var, src_var)); 1408 } 1409 1410 /* 1411 * Like var_assign_integer, only this routine copies the 1412 * supplied "string" into the var named "name". If the var 1413 * named "name" cannot be found then it is first allocated 1414 * before the copy. Space for the string in the var comes 1415 * from interprocess shared memory. If the var "name" 1416 * cannot be found or allocated, or the memory for the 1417 * var_val.string copy of "string" cannot be allocated, the 1418 * routine returns -1, otherwise it returns 0. 1419 */ 1420 int 1421 var_assign_string(char *name, char *string) 1422 { 1423 var_t *var; 1424 char *strptr; 1425 1426 name += 1; 1427 1428 if ((var = var_find(name)) == NULL) 1429 var = var_alloc(name); 1430 1431 if (var == NULL) { 1432 filebench_log(LOG_ERROR, "Cannot assign variable %s", 1433 name); 1434 return (-1); 1435 } 1436 1437 if ((var->var_type & VAR_TYPE_MASK) == VAR_TYPE_RANDOM) { 1438 filebench_log(LOG_ERROR, 1439 "Cannot assign string to random variable %s", name); 1440 return (-1); 1441 } 1442 1443 if ((strptr = ipc_stralloc(string)) == NULL) { 1444 filebench_log(LOG_ERROR, "Cannot assign variable %s", 1445 name); 1446 return (-1); 1447 } 1448 VAR_SET_STR(var, strptr); 1449 1450 filebench_log(LOG_DEBUG_SCRIPT, 1451 "Var assign string $%s=%s", name, string); 1452 1453 return (0); 1454 } 1455 1456 /* 1457 * Allocates a local var. The then extracts the var_string from 1458 * the var named "string" and copies it into the var_string 1459 * of the var "name", after first allocating a piece of 1460 * interprocess shared string memory. Returns a pointer to the 1461 * newly allocated local var or NULL on error. 1462 */ 1463 var_t * 1464 var_lvar_assign_var(char *name, char *src_name) 1465 { 1466 var_t *dst_var, *src_var; 1467 1468 src_name += 1; 1469 1470 if ((src_var = var_find(src_name)) == NULL) { 1471 filebench_log(LOG_ERROR, 1472 "Cannot find source variable %s", src_name); 1473 return (NULL); 1474 } 1475 1476 dst_var = var_lvar_alloc_local(name); 1477 1478 if (dst_var == NULL) { 1479 filebench_log(LOG_ERROR, "Cannot assign variable %s", 1480 name); 1481 return (NULL); 1482 } 1483 1484 /* 1485 * if referencing another local var which is currently 1486 * empty, indirect to it 1487 */ 1488 if ((src_var->var_type & VAR_TYPE_MASK) == VAR_TYPE_LOCAL) { 1489 VAR_SET_INDVAR(dst_var, src_var); 1490 filebench_log(LOG_DEBUG_SCRIPT, 1491 "Assign local var %s to %s", name, src_name); 1492 return (dst_var); 1493 } 1494 1495 if (VAR_HAS_BOOLEAN(src_var)) { 1496 VAR_SET_BOOL(dst_var, src_var->var_val.boolean); 1497 filebench_log(LOG_DEBUG_SCRIPT, 1498 "Assign var (%s, %p)=%s", name, 1499 dst_var, src_var->var_val.boolean?"true":"false"); 1500 } else if (VAR_HAS_INTEGER(src_var)) { 1501 VAR_SET_INT(dst_var, src_var->var_val.integer); 1502 filebench_log(LOG_DEBUG_SCRIPT, 1503 "Assign var (%s, %p)=%llu", name, 1504 dst_var, (u_longlong_t)src_var->var_val.integer); 1505 } else if (VAR_HAS_STRING(src_var)) { 1506 char *strptr; 1507 1508 if ((strptr = ipc_stralloc(src_var->var_val.string)) == NULL) { 1509 filebench_log(LOG_ERROR, 1510 "Cannot assign variable %s", 1511 name); 1512 return (NULL); 1513 } 1514 VAR_SET_STR(dst_var, strptr); 1515 filebench_log(LOG_DEBUG_SCRIPT, 1516 "Assign var (%s, %p)=%s", name, 1517 dst_var, src_var->var_val.string); 1518 } else if (VAR_HAS_DOUBLE(src_var)) { 1519 /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */ 1520 VAR_SET_INT(dst_var, src_var->var_val.dbl_flt); 1521 filebench_log(LOG_DEBUG_SCRIPT, 1522 "Assign var (%s, %p)=%8.2f", name, 1523 dst_var, src_var->var_val.dbl_flt); 1524 } else if (VAR_HAS_RANDDIST(src_var)) { 1525 VAR_SET_RAND(dst_var, src_var->var_val.randptr); 1526 filebench_log(LOG_DEBUG_SCRIPT, 1527 "Assign var (%s, %p)=%llu", name, 1528 dst_var, (u_longlong_t)src_var->var_val.integer); 1529 } 1530 1531 return (dst_var); 1532 } 1533 1534 /* 1535 * the routine allocates a new local var and sets 1536 * its var_boolean's value to that of the supplied 1537 * boolean. It returns a pointer to the new local var 1538 */ 1539 var_t * 1540 var_lvar_assign_boolean(char *name, boolean_t bool) 1541 { 1542 var_t *var; 1543 1544 var = var_lvar_alloc_local(name); 1545 1546 if (var == NULL) { 1547 filebench_log(LOG_ERROR, "Cannot assign variable %s", 1548 name); 1549 return (NULL); 1550 } 1551 1552 VAR_SET_BOOL(var, bool); 1553 1554 filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%s", 1555 name, bool ? "true" : "false"); 1556 1557 return (var); 1558 } 1559 1560 /* 1561 * the routine allocates a new local var and sets 1562 * its var_integers's value to that of the supplied 1563 * integer. It returns a pointer to the new local var 1564 */ 1565 var_t * 1566 var_lvar_assign_integer(char *name, fbint_t integer) 1567 { 1568 var_t *var; 1569 1570 var = var_lvar_alloc_local(name); 1571 1572 if (var == NULL) { 1573 filebench_log(LOG_ERROR, "Cannot assign variable %s", 1574 name); 1575 return (NULL); 1576 } 1577 1578 VAR_SET_INT(var, integer); 1579 1580 filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%llu", 1581 name, (u_longlong_t)integer); 1582 1583 return (var); 1584 } 1585 1586 /* 1587 * the routine allocates a new local var and sets 1588 * its var_dbl_flt value to that of the supplied 1589 * double precission floating point number. It returns 1590 * a pointer to the new local var 1591 */ 1592 var_t * 1593 var_lvar_assign_double(char *name, double dbl) 1594 { 1595 var_t *var; 1596 1597 var = var_lvar_alloc_local(name); 1598 1599 if (var == NULL) { 1600 filebench_log(LOG_ERROR, "Cannot assign variable %s", 1601 name); 1602 return (NULL); 1603 } 1604 1605 VAR_SET_DBL(var, dbl); 1606 1607 filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%8.2f", name, dbl); 1608 1609 return (var); 1610 } 1611 1612 /* 1613 * Like var_lvar_assign_integer, only this routine copies the 1614 * supplied "string" into the var named "name". If the var 1615 * named "name" cannot be found then it is first allocated 1616 * before the copy. Space for the string in the var comes 1617 * from interprocess shared memory. The allocated local var 1618 * is returned at as a char *, or NULL on error. 1619 */ 1620 var_t * 1621 var_lvar_assign_string(char *name, char *string) 1622 { 1623 var_t *var; 1624 char *strptr; 1625 1626 var = var_lvar_alloc_local(name); 1627 1628 if (var == NULL) { 1629 filebench_log(LOG_ERROR, "Cannot assign variable %s", 1630 name); 1631 return (NULL); 1632 } 1633 1634 if ((strptr = ipc_stralloc(string)) == NULL) { 1635 filebench_log(LOG_ERROR, "Cannot assign variable %s", 1636 name); 1637 return (NULL); 1638 } 1639 VAR_SET_STR(var, strptr); 1640 1641 filebench_log(LOG_DEBUG_SCRIPT, 1642 "Lvar_assign_string (%s, %p)=%s", name, var, string); 1643 1644 return (var); 1645 } 1646 1647 /* 1648 * Tests to see if the supplied variable name without the portion after 1649 * the last period is that of a random variable. If it is, it returns 1650 * the number of characters to backspace to skip the period and field 1651 * name. Otherwise it returns 0. 1652 */ 1653 int 1654 var_is_set4_randvar(char *name) 1655 { 1656 var_t *var; 1657 char varname[128]; 1658 int namelength; 1659 char *sp; 1660 1661 (void) strncpy(varname, name, 128); 1662 namelength = strlen(varname); 1663 sp = varname + namelength; 1664 1665 while (sp != varname) { 1666 int c = *sp; 1667 1668 *sp = 0; 1669 if (c == '.') 1670 break; 1671 1672 sp--; 1673 } 1674 1675 /* not a variable name + field? */ 1676 if (sp == varname) 1677 return (0); 1678 1679 /* first part not a variable name? */ 1680 if ((var = var_find(varname+1)) == NULL) 1681 return (0); 1682 1683 /* Make sure it is a random variable */ 1684 if ((var->var_type & VAR_TYPE_MASK) != VAR_TYPE_RANDOM) 1685 return (0); 1686 1687 /* calculate offset from end of random variable name */ 1688 return (namelength - (sp - varname)); 1689 } 1690 1691 /* 1692 * Implements a simple path name like scheme for finding values 1693 * to place in certain specially named vars. The first part of 1694 * the name is interpreted as a category of either: stats, 1695 * eventgen, date, script, or host var. If a match is found, 1696 * the appropriate routine is called to fill in the requested 1697 * value in the provided var_t, and a pointer to the supplied 1698 * var_t is returned. If the requested value is not found, NULL 1699 * is returned. 1700 */ 1701 static var_t * 1702 var_find_internal(var_t *var) 1703 { 1704 char *n = fb_stralloc(var->var_name); 1705 char *name = n; 1706 var_t *rtn = NULL; 1707 1708 name++; 1709 if (name[strlen(name) - 1] != '}') 1710 return (NULL); 1711 name[strlen(name) - 1] = 0; 1712 1713 if (strncmp(name, STATS_VAR, strlen(STATS_VAR)) == 0) 1714 rtn = stats_findvar(var, name + strlen(STATS_VAR)); 1715 1716 if (strcmp(name, EVENTGEN_VAR) == 0) 1717 rtn = eventgen_ratevar(var); 1718 1719 if (strcmp(name, DATE_VAR) == 0) 1720 rtn = date_var(var); 1721 1722 if (strcmp(name, SCRIPT_VAR) == 0) 1723 rtn = script_var(var); 1724 1725 if (strcmp(name, HOST_VAR) == 0) 1726 rtn = host_var(var); 1727 1728 free(n); 1729 1730 return (rtn); 1731 } 1732 1733 /* 1734 * Calls the C library routine getenv() to obtain the value 1735 * for the environment variable specified by var->var_name. 1736 * If found, the value string is returned in var->var_val.string. 1737 * If the requested value is not found, NULL is returned. 1738 */ 1739 static var_t * 1740 var_find_environment(var_t *var) 1741 { 1742 char *n = fb_stralloc(var->var_name); 1743 char *name = n; 1744 char *strptr; 1745 1746 name++; 1747 if (name[strlen(name) - 1] != ')') { 1748 free(n); 1749 return (NULL); 1750 } 1751 name[strlen(name) - 1] = 0; 1752 1753 if ((strptr = getenv(name)) != NULL) { 1754 free(n); 1755 VAR_SET_STR(var, strptr); 1756 return (var); 1757 } else { 1758 free(n); 1759 return (NULL); 1760 } 1761 } 1762 1763 /* 1764 * Look up special variables. The "name" argument is used to find 1765 * the desired special var and fill it with an appropriate string 1766 * value. Looks for an already allocated var of the same name on 1767 * the shm_var_dyn_list. If not found a new dynamic var is allocated. 1768 * if the name begins with '{', it is an internal variable, and 1769 * var_find_internal() is called. If the name begins with '(' it 1770 * is an environment varable, and var_find_environment() is 1771 * called. On success, a pointer to the var_t is returned, 1772 * otherwise, NULL is returned. 1773 */ 1774 static var_t * 1775 var_find_dynamic(char *name) 1776 { 1777 var_t *var = NULL; 1778 var_t *v = filebench_shm->shm_var_dyn_list; 1779 var_t *rtn; 1780 1781 /* 1782 * Lookup a reference to the var handle for this 1783 * special var 1784 */ 1785 for (v = filebench_shm->shm_var_dyn_list; v != NULL; v = v->var_next) { 1786 if (strcmp(v->var_name, name) == 0) { 1787 var = v; 1788 break; 1789 } 1790 } 1791 1792 if (var == NULL) 1793 var = var_alloc_dynamic(name); 1794 1795 /* Internal system control variable */ 1796 if (*name == '{') { 1797 rtn = var_find_internal(var); 1798 if (rtn == NULL) 1799 filebench_log(LOG_ERROR, 1800 "Cannot find internal variable %s", 1801 var->var_name); 1802 return (rtn); 1803 } 1804 1805 /* Lookup variable in environment */ 1806 if (*name == '(') { 1807 rtn = var_find_environment(var); 1808 if (rtn == NULL) 1809 filebench_log(LOG_ERROR, 1810 "Cannot find environment variable %s", 1811 var->var_name); 1812 return (rtn); 1813 } 1814 1815 return (NULL); 1816 } 1817 1818 /* 1819 * replace the avd_t attribute value descriptor in the new FLOW_MASTER flowop 1820 * that points to a local variable with a new avd_t containing 1821 * the actual value from the local variable. 1822 */ 1823 void 1824 avd_update(avd_t *avdp, var_t *lvar_list) 1825 { 1826 var_t *old_lvar, *new_lvar; 1827 1828 if ((*avdp)->avd_type == AVD_IND_VAR) { 1829 1830 /* Make sure there is a local var */ 1831 if ((old_lvar = (*avdp)->avd_val.varptr) == NULL) { 1832 filebench_log(LOG_ERROR, 1833 "avd_update: local var not found"); 1834 return; 1835 } 1836 } else { 1837 /* Empty or not indirect, so no update needed */ 1838 return; 1839 } 1840 1841 /* allocate a new avd using the new or old lvar contents */ 1842 if ((new_lvar = 1843 var_find_list(old_lvar->var_name, lvar_list)) != NULL) 1844 (*avdp) = avd_alloc_var_ptr(new_lvar); 1845 else 1846 (*avdp) = avd_alloc_var_ptr(old_lvar); 1847 } 1848 1849 void 1850 var_update_comp_lvars(var_t *newlvar, var_t *proto_comp_vars, 1851 var_t *mstr_lvars) 1852 { 1853 var_t *proto_lvar; 1854 1855 /* find the prototype lvar from the inherited list */ 1856 proto_lvar = var_find_list_only(newlvar->var_name, proto_comp_vars); 1857 1858 if (proto_lvar == NULL) 1859 return; 1860 1861 /* 1862 * if the new local variable has not already been assigned 1863 * a value, try to copy a value from the prototype local variable 1864 */ 1865 if ((newlvar->var_type & VAR_TYPE_SET_MASK) == 0) { 1866 1867 /* copy value from prototype lvar to new lvar */ 1868 (void) var_copy(newlvar, proto_lvar); 1869 } 1870 1871 /* If proto lvar is indirect, see if we can colapse indirection */ 1872 if (VAR_HAS_INDVAR(proto_lvar)) { 1873 var_t *uplvp; 1874 1875 uplvp = (var_t *)proto_lvar->var_varptr1; 1876 1877 /* search for more current uplvar on comp master list */ 1878 if (mstr_lvars) { 1879 uplvp = var_find_list_only( 1880 uplvp->var_name, mstr_lvars); 1881 VAR_SET_INDVAR(newlvar, uplvp); 1882 } 1883 1884 if (VAR_HAS_INDVAR(uplvp)) 1885 VAR_SET_INDVAR(newlvar, uplvp->var_varptr1); 1886 } 1887 }