xref: /onnv-gate/usr/src/cmd/filebench/common/eventgen.c (revision 9801:4a9784073e11)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Portions Copyright 2008 Denis Cheng
26  */
27 
28 /*
29  * The event generator in this module is the producer half of a
30  * metering system which blocks flows using consumer routines in the
31  * flowop_library.c module. Four routines in that module can limit rates
32  * by event rate (flowoplib_eventlimit), by I/O operations rate
33  * (flowoplib_iopslimit()), by operations rate (flowoplib_opslimit),
34  * or by I/O bandwidth limit (flowoplib_bwlimit). By setting appropriate
35  * event generation rates, required calls per second, I/O ops per second,
36  * file system ops per second, or I/O bandwidth per second limits can
37  * be set. Note, the generated events are shared with all consumer
38  * flowops, of which their will be one for each process / thread
39  * instance which has a consumer flowop defined in it.
40  */
41 
42 #include <sys/time.h>
43 
44 #include "filebench.h"
45 #include "vars.h"
46 #include "eventgen.h"
47 #include "flowop.h"
48 #include "ipc.h"
49 
50 /*
51  * Prints "how to use" information for the eventgen module
52  */
53 void
eventgen_usage(void)54 eventgen_usage(void)
55 {
56 	(void) fprintf(stderr, "eventgen rate=<rate>\n");
57 	(void) fprintf(stderr, "\n");
58 }
59 
60 /*
61  * The producer side of the event system.
62  * Once eventgen_hz has been set by eventgen_setrate(),
63  * the routine sends eventgen_hz events per second until
64  * the program terminates. Events are posted by incrementing
65  * filebench_shm->shm_eventgen_q by the number of generated
66  * events then signalling the condition variable
67  * filebench_shm->shm_eventgen_cv to indicate to event consumers
68  * that more events are available.
69  *
70  * Eventgen_thread attempts to sleep for 10 event periods,
71  * then, once awakened, determines how many periods actually
72  * passed since sleeping, and issues a set of events equal
73  * to the number of periods that it slept, thus keeping the
74  * average rate at the requested rate.
75  */
76 static void
eventgen_thread(void)77 eventgen_thread(void)
78 {
79 	hrtime_t last;
80 
81 	last = gethrtime();
82 	filebench_shm->shm_eventgen_enabled = FALSE;
83 
84 	/* CONSTCOND */
85 	while (1) {
86 		struct timespec sleeptime;
87 		hrtime_t delta;
88 		int count, rate;
89 
90 		if (filebench_shm->shm_eventgen_hz == NULL) {
91 			(void) sleep(1);
92 			continue;
93 		} else {
94 			rate = avd_get_int(filebench_shm->shm_eventgen_hz);
95 			if (rate > 0) {
96 				filebench_shm->shm_eventgen_enabled = TRUE;
97 			} else {
98 				continue;
99 			}
100 		}
101 
102 		/* Sleep for 10xperiod */
103 		sleeptime.tv_sec = 0;
104 		sleeptime.tv_nsec = FB_SEC2NSEC / rate;
105 
106 		sleeptime.tv_nsec *= 10;
107 		if (sleeptime.tv_nsec < 1000UL)
108 			sleeptime.tv_nsec = 1000UL;
109 
110 		sleeptime.tv_sec = sleeptime.tv_nsec / FB_SEC2NSEC;
111 		if (sleeptime.tv_sec > 0)
112 			sleeptime.tv_nsec -= (sleeptime.tv_sec * FB_SEC2NSEC);
113 
114 		(void) nanosleep(&sleeptime, NULL);
115 		delta = gethrtime() - last;
116 		last = gethrtime();
117 		count = (rate * delta) / FB_SEC2NSEC;
118 
119 		filebench_log(LOG_DEBUG_SCRIPT,
120 		    "delta %llums count %d",
121 		    (u_longlong_t)(delta / 1000000), count);
122 
123 		/* Send 'count' events */
124 		(void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
125 		/* Keep the producer with a max of 5 second depth */
126 		if (filebench_shm->shm_eventgen_q < (5 * rate))
127 			filebench_shm->shm_eventgen_q += count;
128 
129 		(void) pthread_cond_signal(&filebench_shm->shm_eventgen_cv);
130 
131 		(void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock);
132 	}
133 }
134 
135 /*
136  * Creates a thread to run the event generator eventgen_thread
137  * routine. Shuts down filebench if the eventgen thread cannot
138  * be created.
139  */
140 void
eventgen_init(void)141 eventgen_init(void)
142 {
143 	/*
144 	 * Linux does not like it if the first
145 	 * argument to pthread_create is null. It actually
146 	 * segv's. -neel
147 	 */
148 	pthread_t tid;
149 
150 	if (pthread_create(&tid, NULL,
151 	    (void *(*)(void*))eventgen_thread, 0) != 0) {
152 		filebench_log(LOG_ERROR, "create timer thread failed: %s",
153 		    strerror(errno));
154 		filebench_shutdown(1);
155 	}
156 }
157 
158 /*
159  * Puts the current event rate in the integer portion of the
160  * supplied var_t. Returns a pointer to the var_t.
161  */
162 var_t *
eventgen_ratevar(var_t * var)163 eventgen_ratevar(var_t *var)
164 {
165 	VAR_SET_INT(var, avd_get_int(filebench_shm->shm_eventgen_hz));
166 	return (var);
167 }
168 
169 /*
170  * Sets the event generator rate to that supplied by
171  * var_t *rate.
172  */
173 void
eventgen_setrate(avd_t rate)174 eventgen_setrate(avd_t rate)
175 {
176 	filebench_shm->shm_eventgen_hz = rate;
177 	if (rate == NULL) {
178 		filebench_log(LOG_ERROR,
179 		    "eventgen_setrate() called without a rate");
180 		return;
181 	}
182 
183 	if (AVD_IS_VAR(rate)) {
184 		filebench_log(LOG_VERBOSE,
185 		    "Eventgen rate taken from variable");
186 	} else {
187 		filebench_log(LOG_VERBOSE, "Eventgen: %llu per second",
188 		    (u_longlong_t)avd_get_int(rate));
189 	}
190 }
191 
192 /*
193  * Clears the event queue so we have a clean start
194  */
195 void
eventgen_reset(void)196 eventgen_reset(void)
197 {
198 	filebench_shm->shm_eventgen_q = 0;
199 }
200