xref: /onnv-gate/usr/src/cmd/filebench/common/misc.c (revision 6084:d5f45b4dae7e)
15184Sek110237 /*
25184Sek110237  * CDDL HEADER START
35184Sek110237  *
45184Sek110237  * The contents of this file are subject to the terms of the
55184Sek110237  * Common Development and Distribution License (the "License").
65184Sek110237  * You may not use this file except in compliance with the License.
75184Sek110237  *
85184Sek110237  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95184Sek110237  * or http://www.opensolaris.org/os/licensing.
105184Sek110237  * See the License for the specific language governing permissions
115184Sek110237  * and limitations under the License.
125184Sek110237  *
135184Sek110237  * When distributing Covered Code, include this CDDL HEADER in each
145184Sek110237  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155184Sek110237  * If applicable, add the following below this CDDL HEADER, with the
165184Sek110237  * fields enclosed by brackets "[]" replaced with your own identifying
175184Sek110237  * information: Portions Copyright [yyyy] [name of copyright owner]
185184Sek110237  *
195184Sek110237  * CDDL HEADER END
205184Sek110237  */
215184Sek110237 /*
22*6084Saw148015  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235184Sek110237  * Use is subject to license terms.
245184Sek110237  */
255184Sek110237 
265184Sek110237 #pragma ident	"%Z%%M%	%I%	%E% SMI"
275184Sek110237 
285184Sek110237 #include <stdio.h>
295184Sek110237 #include <fcntl.h>
305184Sek110237 #include <limits.h>
315184Sek110237 #include <time.h>
325184Sek110237 #include <libgen.h>
335184Sek110237 #include <unistd.h>
345184Sek110237 #include <strings.h>
355184Sek110237 #include "filebench.h"
365184Sek110237 #include "ipc.h"
375184Sek110237 #include "eventgen.h"
385184Sek110237 #include "utils.h"
395184Sek110237 
405184Sek110237 /*
415184Sek110237  * Routines to access high resolution system time, initialize and
425184Sek110237  * shutdown filebench, obtain system generated random numbers from
435184Sek110237  * "urandom", log filebench run progress and errors, and access system
445184Sek110237  * information strings.
455184Sek110237  */
465184Sek110237 
475184Sek110237 
485184Sek110237 #if !defined(sun) && defined(USE_RDTSC)
495184Sek110237 /*
505184Sek110237  * Lets us use the rdtsc instruction to get highres time.
515184Sek110237  * Thanks to libmicro
525184Sek110237  */
535184Sek110237 uint64_t	cpu_hz = 0;
545184Sek110237 
555184Sek110237 /*
565184Sek110237  * Uses the rdtsc instruction to get high resolution (cpu
575184Sek110237  * clock ticks) time. Only used for non Sun compiles.
585184Sek110237  */
595184Sek110237 __inline__ long long
605184Sek110237 rdtsc(void)
615184Sek110237 {
625184Sek110237 	unsigned long long x;
635184Sek110237 	__asm__ volatile(".byte 0x0f, 0x31" : "=A" (x));
645184Sek110237 	return (x);
655184Sek110237 }
665184Sek110237 
675184Sek110237 /*
685184Sek110237  * Get high resolution time in nanoseconds. This is the version
695184Sek110237  * used when not compiled for Sun systems. It uses rdtsc call to
705184Sek110237  * get clock ticks and converts to nanoseconds
715184Sek110237  */
725184Sek110237 uint64_t
735184Sek110237 gethrtime(void)
745184Sek110237 {
755184Sek110237 	uint64_t hrt;
765184Sek110237 
775184Sek110237 	/* convert to nanosecs and return */
785184Sek110237 	hrt = 1000000000UL * rdtsc() / cpu_hz;
795184Sek110237 	return (hrt);
805184Sek110237 }
815184Sek110237 
825184Sek110237 /*
835184Sek110237  * Gets CPU clock frequency in MHz from cpuinfo file.
845184Sek110237  * Converts to cpu_hz and stores in cpu_hz global uint64_t.
855184Sek110237  * Only used for non Sun compiles.
865184Sek110237  */
875184Sek110237 static uint64_t
885184Sek110237 parse_cpu_hz(void)
895184Sek110237 {
905184Sek110237 	/*
915184Sek110237 	 * Parse the following from /proc/cpuinfo.
925184Sek110237 	 * cpu MHz		: 2191.563
935184Sek110237 	 */
945184Sek110237 	FILE *cpuinfo;
955184Sek110237 	double hertz = -1;
965184Sek110237 	uint64_t hz;
975184Sek110237 
985184Sek110237 	if ((cpuinfo = fopen("/proc/cpuinfo", "r")) == NULL) {
995184Sek110237 		filebench_log(LOG_ERROR, "open /proc/cpuinfo failed: %s",
1005184Sek110237 		    strerror(errno));
1015184Sek110237 		filebench_shutdown(1);
1025184Sek110237 	}
1035184Sek110237 	while (!feof(cpuinfo)) {
1045184Sek110237 		char buffer[80];
1055184Sek110237 
1065184Sek110237 		fgets(buffer, 80, cpuinfo);
1075184Sek110237 		if (strlen(buffer) == 0) continue;
1085184Sek110237 		if (strncasecmp(buffer, "cpu MHz", 7) == 0) {
1095184Sek110237 			char *token = strtok(buffer, ":");
1105184Sek110237 
1115184Sek110237 			if (token != NULL) {
1125184Sek110237 				token = strtok((char *)NULL, ":");
1135184Sek110237 				hertz = strtod(token, NULL);
1145184Sek110237 			}
1155184Sek110237 			break;
1165184Sek110237 		}
1175184Sek110237 	}
1185184Sek110237 	printf("CPU Mhz %9.6f, sysconf:%ld\n", hertz, sysconf(_SC_CLK_TCK));
1195184Sek110237 	hz = hertz * 1000000;
1205184Sek110237 
1215184Sek110237 	return (hz);
1225184Sek110237 }
1235184Sek110237 
1245184Sek110237 #elif !defined(sun)
1255184Sek110237 
1265184Sek110237 /*
1275184Sek110237  * Get high resolution time in nanoseconds. This is the version
1285184Sek110237  * used if compiled for Sun systems. It calls gettimeofday
1295184Sek110237  * to get current time and converts it to nanoseconds.
1305184Sek110237  */
1315184Sek110237 uint64_t
1325184Sek110237 gethrtime(void)
1335184Sek110237 {
1345184Sek110237 	struct timeval tv;
1355184Sek110237 	uint64_t hrt;
1365184Sek110237 
1375184Sek110237 	gettimeofday(&tv, NULL);
1385184Sek110237 
1395184Sek110237 	hrt = (uint64_t)tv.tv_sec * 1000000000UL +
1405184Sek110237 	    (uint64_t)tv.tv_usec * 1000UL;
1415184Sek110237 	return (hrt);
1425184Sek110237 }
1435184Sek110237 #endif
1445184Sek110237 
1455184Sek110237 static int urandomfd;
1465184Sek110237 
1475184Sek110237 /*
1485184Sek110237  * Main filebench initialization. Opens the random number
1495184Sek110237  * "device" file or shuts down the run if one is not found.
1505184Sek110237  * Sets the cpu clock frequency variable or shuts down the
1515184Sek110237  * run if one is not found.
1525184Sek110237  */
1535184Sek110237 void
1545184Sek110237 filebench_init(void)
1555184Sek110237 {
1565184Sek110237 	/* open the "urandom" random number device file */
1575184Sek110237 	if ((urandomfd = open("/dev/urandom", O_RDONLY)) < 0) {
1585184Sek110237 		filebench_log(LOG_ERROR, "open /dev/urandom failed: %s",
1595184Sek110237 		    strerror(errno));
1605184Sek110237 		filebench_shutdown(1);
1615184Sek110237 	}
1625184Sek110237 #if defined(USE_RDTSC) && (LINUX_PORT)
1635184Sek110237 	cpu_hz = parse_cpu_hz();
1645184Sek110237 	if (cpu_hz <= 0) {
1655184Sek110237 		filebench_log(LOG_ERROR, "Error getting CPU Mhz: %s",
1665184Sek110237 		    strerror(errno));
1675184Sek110237 		filebench_shutdown(1);
1685184Sek110237 	}
1695184Sek110237 #endif /* USE_RDTSC */
1705184Sek110237 
1715184Sek110237 }
1725184Sek110237 
1735184Sek110237 /*
1745184Sek110237  * Reads a 64 bit random number from the urandom "file".
1755184Sek110237  * Shuts down the run if the read fails. Otherwise returns
1765184Sek110237  * the random number after rounding it off by "round".
1775184Sek110237  * Returns 0 on success, -1 on failure.
1785184Sek110237  */
1795184Sek110237 int
1805184Sek110237 filebench_randomno64(uint64_t *randp, uint64_t max, uint64_t round)
1815184Sek110237 {
1825184Sek110237 	uint64_t random;
1835184Sek110237 
1845184Sek110237 	/* check for round value too large */
1855184Sek110237 	if (max <= round) {
1865184Sek110237 		*randp = 0;
1875184Sek110237 
1885184Sek110237 		/* if it just fits, its ok, otherwise error */
1895184Sek110237 		if (max == round)
1905184Sek110237 			return (0);
1915184Sek110237 		else
1925184Sek110237 			return (-1);
1935184Sek110237 	}
1945184Sek110237 
1955184Sek110237 	if (read(urandomfd, &random,
1965184Sek110237 	    sizeof (uint64_t)) != sizeof (uint64_t)) {
1975184Sek110237 		filebench_log(LOG_ERROR, "read /dev/urandom failed: %s",
1985184Sek110237 		    strerror(errno));
1995184Sek110237 		filebench_shutdown(1);
2005184Sek110237 	}
2015184Sek110237 
2025184Sek110237 	/* clip with max and optionally round */
2035184Sek110237 	max -= round;
2045184Sek110237 	random = random / (FILEBENCH_RANDMAX64 / max);
2055184Sek110237 	if (round) {
2065184Sek110237 		random = random / round;
2075184Sek110237 		random *= round;
2085184Sek110237 	}
2095184Sek110237 	if (random > max)
2105184Sek110237 		random = max;
2115184Sek110237 
2125184Sek110237 	*randp = random;
2135184Sek110237 	return (0);
2145184Sek110237 }
2155184Sek110237 
2165184Sek110237 
2175184Sek110237 /*
2185184Sek110237  * Reads a 32 bit random number from the urandom "file".
2195184Sek110237  * Shuts down the run if the read fails. Otherwise returns
2205184Sek110237  * the random number after rounding it off by "round".
2215184Sek110237  * Returns 0 on success, -1 on failure.
2225184Sek110237  */
2235184Sek110237 int
2245184Sek110237 filebench_randomno32(uint32_t *randp, uint32_t max, uint32_t round)
2255184Sek110237 {
2265184Sek110237 	uint32_t random;
2275184Sek110237 
2285184Sek110237 	/* check for round value too large */
2295184Sek110237 	if (max <= round) {
2305184Sek110237 		*randp = 0;
2315184Sek110237 
2325184Sek110237 		/* if it just fits, its ok, otherwise error */
2335184Sek110237 		if (max == round)
2345184Sek110237 			return (0);
2355184Sek110237 		else
2365184Sek110237 			return (-1);
2375184Sek110237 	}
2385184Sek110237 
2395184Sek110237 	if (read(urandomfd, &random,
2405184Sek110237 	    sizeof (uint32_t)) != sizeof (uint32_t)) {
2415184Sek110237 		filebench_log(LOG_ERROR, "read /dev/urandom failed: %s",
2425184Sek110237 		    strerror(errno));
2435184Sek110237 		filebench_shutdown(1);
2445184Sek110237 	}
2455184Sek110237 
2465184Sek110237 	/* clip with max and optionally round */
2475184Sek110237 	max -= round;
2485184Sek110237 	random = random / (FILEBENCH_RANDMAX32 / max);
2495184Sek110237 	if (round) {
2505184Sek110237 		random = random / round;
2515184Sek110237 		random *= round;
2525184Sek110237 	}
2535184Sek110237 	if (random > max)
2545184Sek110237 		random = max;
2555184Sek110237 
2565184Sek110237 	*randp = random;
2575184Sek110237 	return (0);
2585184Sek110237 }
2595184Sek110237 
2605184Sek110237 extern int lex_lineno;
2615184Sek110237 
2625184Sek110237 /*
2635184Sek110237  * Writes a message consisting of information formated by
2645184Sek110237  * "fmt" to the log file, dump file or stdout.  The supplied
2655184Sek110237  * "level" argument determines which file to write to and
2665184Sek110237  * what other actions to take. The level LOG_LOG writes to
2675184Sek110237  * the "log" file, and will open the file on the first
2685184Sek110237  * invocation. The level LOG_DUMP writes to the "dump" file,
2695184Sek110237  * and will open it on the first invocation. Other levels
2705184Sek110237  * print to the stdout device, with the amount of information
2715184Sek110237  * dependent on the error level and the current error level
2725184Sek110237  * setting in filebench_shm->debug_level.
2735184Sek110237  */
2745184Sek110237 void filebench_log
2755184Sek110237 __V((int level, const char *fmt, ...))
2765184Sek110237 {
2775184Sek110237 	va_list args;
2785184Sek110237 	hrtime_t now;
2795184Sek110237 	char line[131072];
2805184Sek110237 	char buf[131072];
2815184Sek110237 
2825184Sek110237 	if (level == LOG_FATAL)
2835184Sek110237 		goto fatal;
2845184Sek110237 
2855184Sek110237 	/* open logfile if not already open and writing to it */
2865184Sek110237 	if ((level == LOG_LOG) &&
2875184Sek110237 	    (filebench_shm->log_fd < 0)) {
2885184Sek110237 		char path[MAXPATHLEN];
2895184Sek110237 		char *s;
2905184Sek110237 
2915184Sek110237 		(void) strcpy(path, filebench_shm->fscriptname);
2925184Sek110237 		if ((s = strstr(path, ".f")))
2935184Sek110237 			*s = 0;
2945184Sek110237 		else
2955184Sek110237 			(void) strcpy(path, "filebench");
2965184Sek110237 
2975184Sek110237 		(void) strcat(path, ".csv");
2985184Sek110237 
2995184Sek110237 		filebench_shm->log_fd =
3005184Sek110237 		    open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
3015184Sek110237 	}
3025184Sek110237 
3035184Sek110237 	/*
3045184Sek110237 	 * if logfile still not open, switch to LOG_ERROR level so
3055184Sek110237 	 * it gets reported to stdout
3065184Sek110237 	 */
3075184Sek110237 	if ((level == LOG_LOG) &&
3085184Sek110237 	    (filebench_shm->log_fd < 0)) {
3095184Sek110237 		(void) snprintf(line, sizeof (line),  "Open logfile failed: %s",
3105184Sek110237 		    strerror(errno));
3115184Sek110237 		level = LOG_ERROR;
3125184Sek110237 	}
3135184Sek110237 
3145184Sek110237 	/* open dumpfile if not already open and writing to it */
3155184Sek110237 	if ((level == LOG_DUMP) &&
3165184Sek110237 	    (*filebench_shm->dump_filename == 0))
3175184Sek110237 		return;
3185184Sek110237 
3195184Sek110237 	if ((level == LOG_DUMP) &&
3205184Sek110237 	    (filebench_shm->dump_fd < 0)) {
3215184Sek110237 
3225184Sek110237 		filebench_shm->dump_fd =
3235184Sek110237 		    open(filebench_shm->dump_filename,
3245184Sek110237 		    O_RDWR | O_CREAT | O_TRUNC, 0666);
3255184Sek110237 	}
3265184Sek110237 
3275184Sek110237 	if ((level == LOG_DUMP) &&
3285184Sek110237 	    (filebench_shm->dump_fd < 0)) {
3295184Sek110237 		(void) snprintf(line, sizeof (line), "Open logfile failed: %s",
3305184Sek110237 		    strerror(errno));
3315184Sek110237 		level = LOG_ERROR;
3325184Sek110237 	}
3335184Sek110237 
334*6084Saw148015 	/* Quit if this is a LOG_ERROR messages and they are disabled */
335*6084Saw148015 	if ((filebench_shm->shm_1st_err) && (level == LOG_ERROR))
336*6084Saw148015 		return;
337*6084Saw148015 
338*6084Saw148015 	if (level == LOG_ERROR1) {
339*6084Saw148015 		if (filebench_shm->shm_1st_err)
340*6084Saw148015 			return;
341*6084Saw148015 
342*6084Saw148015 		/* A LOG_ERROR1 temporarily disables LOG_ERROR messages */
343*6084Saw148015 		filebench_shm->shm_1st_err = 1;
344*6084Saw148015 		level = LOG_ERROR;
345*6084Saw148015 	}
346*6084Saw148015 
3475184Sek110237 	/* Only log greater than debug setting */
3485184Sek110237 	if ((level != LOG_DUMP) && (level != LOG_LOG) &&
3495184Sek110237 	    (level > filebench_shm->debug_level))
3505184Sek110237 		return;
3515184Sek110237 
3525184Sek110237 	now = gethrtime();
3535184Sek110237 
3545184Sek110237 fatal:
3555184Sek110237 
3565184Sek110237 #ifdef __STDC__
3575184Sek110237 	va_start(args, fmt);
3585184Sek110237 #else
3595184Sek110237 	char *fmt;
3605184Sek110237 	va_start(args);
3615184Sek110237 	fmt = va_arg(args, char *);
3625184Sek110237 #endif
3635184Sek110237 
3645184Sek110237 	(void) vsprintf(line, fmt, args);
3655184Sek110237 
3665184Sek110237 	va_end(args);
3675184Sek110237 
3685184Sek110237 	if (level == LOG_FATAL) {
3695184Sek110237 		(void) fprintf(stdout, "%s\n", line);
3705184Sek110237 		return;
3715184Sek110237 	}
3725184Sek110237 
3735184Sek110237 	/* Serialize messages to log */
3745184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->msg_lock);
3755184Sek110237 
3765184Sek110237 	if (level == LOG_LOG) {
3775184Sek110237 		if (filebench_shm->log_fd > 0) {
3785184Sek110237 			(void) snprintf(buf, sizeof (buf), "%s\n", line);
3795184Sek110237 			(void) write(filebench_shm->log_fd, buf, strlen(buf));
3805184Sek110237 			(void) fsync(filebench_shm->log_fd);
3815184Sek110237 		}
3825184Sek110237 
3835184Sek110237 	} else if (level == LOG_DUMP) {
3845184Sek110237 		if (filebench_shm->dump_fd != -1) {
3855184Sek110237 			(void) snprintf(buf, sizeof (buf), "%s\n", line);
3865184Sek110237 			(void) write(filebench_shm->dump_fd, buf, strlen(buf));
3875184Sek110237 			(void) fsync(filebench_shm->dump_fd);
3885184Sek110237 		}
3895184Sek110237 
3905184Sek110237 	} else if (filebench_shm->debug_level > LOG_INFO) {
3915216Sek110237 		(void) fprintf(stdout, "%5d: %4.3f: %s",
392*6084Saw148015 		    (int)my_pid, (now - filebench_shm->epoch) / FSECS,
3935184Sek110237 		    line);
3945184Sek110237 	} else {
3955184Sek110237 		(void) fprintf(stdout, "%4.3f: %s",
3965184Sek110237 		    (now - filebench_shm->epoch) / FSECS,
3975184Sek110237 		    line);
3985184Sek110237 	}
3995184Sek110237 
4005184Sek110237 	if (level == LOG_ERROR) {
401*6084Saw148015 		if (my_procflow == NULL)
402*6084Saw148015 			(void) fprintf(stdout, " on line %d", lex_lineno);
4035184Sek110237 	}
4045184Sek110237 
4055184Sek110237 	if ((level != LOG_LOG) && (level != LOG_DUMP)) {
4065184Sek110237 		(void) fprintf(stdout, "\n");
4075184Sek110237 		(void) fflush(stdout);
4085184Sek110237 	}
4095184Sek110237 
4105184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->msg_lock);
4115184Sek110237 }
4125184Sek110237 
4135184Sek110237 /*
4145184Sek110237  * Stops the run and exits filebench. If filebench is
4155184Sek110237  * currently running a workload, calls procflow_shutdown()
4165184Sek110237  * to stop the run. Also closes and deletes shared memory.
4175184Sek110237  */
4185184Sek110237 void
4195184Sek110237 filebench_shutdown(int error) {
4205184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "Shutdown");
4215184Sek110237 	(void) unlink("/tmp/filebench_shm");
422*6084Saw148015 	if (filebench_shm->shm_running)
4235184Sek110237 		procflow_shutdown();
4245184Sek110237 	filebench_shm->f_abort = 1;
4255184Sek110237 	ipc_ismdelete();
4265184Sek110237 	exit(error);
4275184Sek110237 }
4285184Sek110237 
4295184Sek110237 /*
4305184Sek110237  * Put the hostname in ${hostname}. The system supplied
4315184Sek110237  * host name string is copied into an allocated string and
4325184Sek110237  * the pointer to the string is placed in the supplied
4335184Sek110237  * variable "var". If var->var_string already points to
4345184Sek110237  * a string, the string is freed. The routine always
4355184Sek110237  * returns zero (0).
4365184Sek110237  */
4375184Sek110237 var_t *
4385184Sek110237 host_var(var_t *var)
4395184Sek110237 {
4405184Sek110237 	char hoststr[128];
4415184Sek110237 
4425184Sek110237 	(void) gethostname(hoststr, 128);
4435184Sek110237 	if (var->var_string)
4445184Sek110237 		free(var->var_string);
4455184Sek110237 	var->var_string = fb_stralloc(hoststr);
4465184Sek110237 	return (0);
4475184Sek110237 }
4485184Sek110237 
4495184Sek110237 /*
4505184Sek110237  * Put the date string in ${date}. The system supplied date is
4515184Sek110237  * copied into an allocated string and the pointer to the string
4525184Sek110237  * is placed in the supplied var_t's var_string. If
4535184Sek110237  * var->var_string already points to a string, the string
4545184Sek110237  * is freed. The routine always returns a pointer to the
4555184Sek110237  * supplied var_t.
4565184Sek110237  */
4575184Sek110237 var_t *
4585184Sek110237 date_var(var_t *var)
4595184Sek110237 {
4605184Sek110237 	char datestr[128];
4615184Sek110237 #ifdef HAVE_CFTIME
4625184Sek110237 	time_t t = time(NULL);
4635184Sek110237 #else
4645184Sek110237 	struct tm t;
4655184Sek110237 #endif
4665184Sek110237 
4675184Sek110237 #ifdef HAVE_CFTIME
4685184Sek110237 	cftime(datestr, "%y%m%d%H" "%M", &t);
4695184Sek110237 #else
4705184Sek110237 	(void) strftime(datestr, sizeof (datestr), "%y%m%d%H %M", &t);
4715184Sek110237 #endif
4725184Sek110237 
4735184Sek110237 	if (var->var_string)
4745184Sek110237 		free(var->var_string);
4755184Sek110237 	var->var_string = fb_stralloc(datestr);
4765184Sek110237 
4775184Sek110237 	return (var);
4785184Sek110237 }
4795184Sek110237 
4805184Sek110237 extern char *fscriptname;
4815184Sek110237 
4825184Sek110237 /*
4835184Sek110237  * Put the script name in ${script}. The path name of the script
4845184Sek110237  * used with this filebench run trimmed of the trailing ".f" and
4855184Sek110237  * all leading subdirectories. The remaining script name is
4865184Sek110237  * copied into the var_string field of the supplied variable
4875184Sek110237  * "var". The routine always returns a pointer to the supplied
4885184Sek110237  * var_t.
4895184Sek110237  */
4905184Sek110237 var_t *
4915184Sek110237 script_var(var_t *var)
4925184Sek110237 {
4935184Sek110237 	char *scriptstr;
4945184Sek110237 	char *f = fb_stralloc(fscriptname);
4955184Sek110237 
4965184Sek110237 	/* Trim the .f suffix */
4975184Sek110237 	for (scriptstr = f + strlen(f) - 1; scriptstr != f; scriptstr--) {
4985184Sek110237 		if (*scriptstr == '.') {
4995184Sek110237 			*scriptstr = 0;
5005184Sek110237 			break;
5015184Sek110237 		}
5025184Sek110237 	}
5035184Sek110237 
5045184Sek110237 	var->var_string = fb_stralloc(basename(f));
5055184Sek110237 	free(f);
5065184Sek110237 
5075184Sek110237 	return (var);
5085184Sek110237 }
509