xref: /onnv-gate/usr/src/cmd/filebench/common/eventgen.c (revision 6613:38664cf1a8a1)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Portions Copyright 2008 Denis Cheng
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 /*
31  * The event generator in this module is the producer half of a
32  * metering system which blocks flows using consumer routines in the
33  * flowop_library.c module. Four routines in that module can limit rates
34  * by event rate (flowoplib_eventlimit), by I/O operations rate
35  * (flowoplib_iopslimit()), by operations rate (flowoplib_opslimit),
36  * or by I/O bandwidth limit (flowoplib_bwlimit). By setting appropriate
37  * event generation rates, required calls per second, I/O ops per second,
38  * file system ops per second, or I/O bandwidth per second limits can
39  * be set. Note, the generated events are shared with all consumer
40  * flowops, of which their will be one for each process / thread
41  * instance which has a consumer flowop defined in it.
42  */
43 
44 #include <sys/time.h>
45 
46 #include "filebench.h"
47 #include "vars.h"
48 #include "eventgen.h"
49 #include "flowop.h"
50 #include "ipc.h"
51 
52 /*
53  * Prints "how to use" information for the eventgen module
54  */
55 void
56 eventgen_usage(void)
57 {
58 	(void) fprintf(stderr, "eventgen rate=<rate>\n");
59 	(void) fprintf(stderr, "\n");
60 }
61 
62 /*
63  * The producer side of the event system.
64  * Once eventgen_hz has been set by eventgen_setrate(),
65  * the routine sends eventgen_hz events per second until
66  * the program terminates. Events are posted by incrementing
67  * filebench_shm->shm_eventgen_q by the number of generated
68  * events then signalling the condition variable
69  * filebench_shm->shm_eventgen_cv to indicate to event consumers
70  * that more events are available.
71  *
72  * Eventgen_thread attempts to sleep for 10 event periods,
73  * then, once awakened, determines how many periods actually
74  * passed since sleeping, and issues a set of events equal
75  * to the number of periods that it slept, thus keeping the
76  * average rate at the requested rate.
77  */
78 static void
79 eventgen_thread(void)
80 {
81 	hrtime_t last;
82 
83 	last = gethrtime();
84 
85 	/* CONSTCOND */
86 	while (1) {
87 		struct timespec sleeptime;
88 		hrtime_t delta;
89 		int count;
90 
91 		if (filebench_shm->shm_eventgen_hz == 0) {
92 			(void) sleep(1);
93 			continue;
94 		}
95 		/* Sleep for 10xperiod */
96 		sleeptime.tv_sec = 0;
97 		sleeptime.tv_nsec = FB_SEC2NSEC /
98 		    filebench_shm->shm_eventgen_hz;
99 
100 		sleeptime.tv_nsec *= 10;
101 		if (sleeptime.tv_nsec < 1000UL)
102 			sleeptime.tv_nsec = 1000UL;
103 
104 		sleeptime.tv_sec = sleeptime.tv_nsec / FB_SEC2NSEC;
105 		if (sleeptime.tv_sec > 0)
106 			sleeptime.tv_nsec -= (sleeptime.tv_sec * FB_SEC2NSEC);
107 
108 		(void) nanosleep(&sleeptime, NULL);
109 		delta = gethrtime() - last;
110 		last = gethrtime();
111 		count = (filebench_shm->shm_eventgen_hz * delta) / FB_SEC2NSEC;
112 
113 		filebench_log(LOG_DEBUG_SCRIPT,
114 		    "delta %llums count %d",
115 		    (u_longlong_t)(delta / 1000000), count);
116 
117 		/* Send 'count' events */
118 		(void) ipc_mutex_lock(&filebench_shm->shm_eventgen_lock);
119 		/* Keep the producer with a max of 5 second depth */
120 		if (filebench_shm->shm_eventgen_q <
121 		    (5 * filebench_shm->shm_eventgen_hz))
122 			filebench_shm->shm_eventgen_q += count;
123 
124 		(void) pthread_cond_signal(&filebench_shm->shm_eventgen_cv);
125 
126 		(void) ipc_mutex_unlock(&filebench_shm->shm_eventgen_lock);
127 	}
128 }
129 
130 /*
131  * Creates a thread to run the event generator eventgen_thread
132  * routine. Shuts down filebench if the eventgen thread cannot
133  * be created.
134  */
135 void
136 eventgen_init(void)
137 {
138 	/*
139 	 * Linux does not like it if the first
140 	 * argument to pthread_create is null. It actually
141 	 * segv's. -neel
142 	 */
143 	pthread_t tid;
144 
145 	if (pthread_create(&tid, NULL,
146 	    (void *(*)(void*))eventgen_thread, 0) != 0) {
147 		filebench_log(LOG_ERROR, "create timer thread failed: %s",
148 		    strerror(errno));
149 		filebench_shutdown(1);
150 	}
151 }
152 
153 /*
154  * Puts the current event rate in the integer portion of the
155  * supplied var_t. Returns a pointer to the var_t.
156  */
157 var_t *
158 eventgen_ratevar(var_t *var)
159 {
160 	VAR_SET_INT(var, filebench_shm->shm_eventgen_hz);
161 	return (var);
162 }
163 
164 /*
165  * Sets the event generator rate to that supplied by
166  * fbint_t rate.
167  */
168 void
169 eventgen_setrate(fbint_t rate)
170 {
171 	filebench_shm->shm_eventgen_hz = (int)rate;
172 }
173 
174 /*
175  * Turns off the event generator by setting the rate to zero
176  */
177 void
178 eventgen_reset(void)
179 {
180 	filebench_shm->shm_eventgen_q = 0;
181 }
182