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