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