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 *
avd_get_type_string(avd_t avd)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 *
var_get_type_string(var_t * ivp)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
avd_get_int(avd_t avd)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
avd_get_dbl(avd_t avd)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
avd_get_bool(avd_t avd)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 *
avd_get_str(avd_t avd)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
avd_alloc_cmn(void)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
avd_bool_alloc(boolean_t bool)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
avd_int_alloc(fbint_t integer)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
avd_alloc_var_ptr(var_t * var)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
avd_str_alloc(char * string)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 *
var_alloc_cmn(char * name,int var_type)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 *
var_lvar_alloc_local(char * name)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 *
var_alloc(char * name)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 *
var_alloc_dynamic(char * name)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 *
var_find(char * name)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 *
var_find_list_only(char * name,var_t * var_list)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 *
var_find_list(char * name,var_t * var_list)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 *
var_find_alloc(char * name)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
var_assign_boolean(char * name,boolean_t bool)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
var_assign_integer(char * name,fbint_t integer)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
var_binary_integer_op(var_t * var)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
var_binary_dbl_flt_op(var_t * var)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
var_assign_op_var_int(char * name,int optype,char * src1,fbint_t src2)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
var_assign_op_var_var(char * name,int optype,char * src1,char * src2)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 *
var_find_randvar(char * name)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 *
var_define_randvar(char * name)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
var_ref_attr(char * name)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 *
var_get_string(var_t * var)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 *
var_to_string(char * name)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
var_get_bool(var_t * var)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
var_get_int(var_t * var)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
var_get_dbl(var_t * var)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
var_to_boolean(char * name)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
var_to_integer(char * name)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
var_to_double(char * name)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 *
var_randvar_to_string(char * name,int param_name)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
var_copy(var_t * dst_var,var_t * src_var)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
var_assign_var(char * name,char * src_name)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
var_assign_string(char * name,char * string)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 *
var_lvar_assign_var(char * name,char * src_name)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 *
var_lvar_assign_boolean(char * name,boolean_t bool)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 *
var_lvar_assign_integer(char * name,fbint_t integer)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 *
var_lvar_assign_double(char * name,double dbl)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 *
var_lvar_assign_string(char * name,char * string)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
var_is_set4_randvar(char * name)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 *
var_find_internal(var_t * var)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 *
var_find_environment(var_t * var)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 *
var_find_dynamic(char * name)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
avd_update(avd_t * avdp,var_t * lvar_list)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
var_update_comp_lvars(var_t * newlvar,var_t * proto_comp_vars,var_t * mstr_lvars)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 }
1888