1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms 5 * of the Common Development and Distribution License 6 * (the "License"). You may not use this file except 7 * in compliance with the License. 8 * 9 * You can obtain a copy of the license at 10 * src/OPENSOLARIS.LICENSE 11 * or http://www.opensolaris.org/os/licensing. 12 * See the License for the specific language governing 13 * permissions and limitations under the License. 14 * 15 * When distributing Covered Code, include this CDDL 16 * HEADER in each file and include the License file at 17 * usr/src/OPENSOLARIS.LICENSE. If applicable, 18 * add the following below this CDDL HEADER, with the 19 * fields enclosed by brackets "[]" replaced with your 20 * own identifying information: Portions Copyright [yyyy] 21 * [name of copyright owner] 22 * 23 * CDDL HEADER END 24 */ 25 26 /* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /* 32 * The "cascade" test case is a multiprocess/multithread batten-passing model 33 * using lock primitives alone for synchronisation. Threads are arranged in a 34 * ring. Each thread has two locks of its own on which it blocks, and is able 35 * to manipulate the two locks belonging to the thread which follows it in the 36 * ring. 37 * 38 * The number of threads (nthreads) is specified by the generic libMicro -P/-T 39 * options. With nthreads == 1 (the default) the uncontended case can be timed. 40 * 41 * The main logic is generic and allows any simple blocking API to be tested. 42 * The API-specific component is clearly indicated. 43 */ 44 45 #include <unistd.h> 46 #include <stdlib.h> 47 #include <stdio.h> 48 #include <fcntl.h> 49 50 #include "libmicro.h" 51 52 typedef struct { 53 int ts_once; 54 int ts_id; 55 int ts_us0; /* our lock indices */ 56 int ts_us1; 57 int ts_them0; /* their lock indices */ 58 int ts_them1; 59 } tsd_t; 60 61 static int nthreads; 62 63 /* 64 * API-specific code BEGINS here 65 */ 66 67 #define DEFD "/tmp" 68 69 static char *optd = DEFD; 70 static int file; 71 static int nlocks; 72 73 int 74 benchmark_init() 75 { 76 lm_tsdsize = sizeof (tsd_t); 77 78 (void) sprintf(lm_optstr, "d:"); 79 80 lm_defN = "cscd_fcntl"; 81 82 (void) sprintf(lm_usage, 83 " [-d directory for temp file (default %s)]\n" 84 "notes: thread cascade using fcntl region locking\n", 85 DEFD); 86 87 return (0); 88 } 89 90 int 91 benchmark_optswitch(int opt, char *optarg) 92 { 93 switch (opt) { 94 case 'd': 95 optd = optarg; 96 break; 97 default: 98 return (-1); 99 } 100 return (0); 101 } 102 103 int 104 benchmark_initrun() 105 { 106 int errors = 0; 107 char fname[1024]; 108 109 nthreads = lm_optP * lm_optT; 110 nlocks = nthreads * 2; 111 112 (void) sprintf(fname, "%s/cascade.%ld", optd, getpid()); 113 114 file = open(fname, O_CREAT | O_TRUNC | O_RDWR, 0600); 115 if (file == -1) { 116 errors++; 117 } 118 119 if (unlink(fname)) { 120 errors++; 121 } 122 123 if (ftruncate(file, nlocks * 3) == -1) { 124 errors++; 125 } 126 127 return (errors); 128 } 129 130 int 131 block(int index) 132 { 133 struct flock fl; 134 135 fl.l_type = F_WRLCK; 136 fl.l_whence = SEEK_SET; 137 fl.l_start = index; 138 fl.l_len = 1; 139 return (fcntl(file, F_SETLKW, &fl) == -1); 140 } 141 142 int 143 unblock(int index) 144 { 145 struct flock fl; 146 147 fl.l_type = F_UNLCK; 148 fl.l_whence = SEEK_SET; 149 fl.l_start = index; 150 fl.l_len = 1; 151 return (fcntl(file, F_SETLK, &fl) == -1); 152 } 153 154 /* 155 * API-specific code ENDS here 156 */ 157 158 int 159 benchmark_initbatch(void *tsd) 160 { 161 tsd_t *ts = (tsd_t *)tsd; 162 int e = 0; 163 164 if (ts->ts_once == 0) { 165 int us, them; 166 167 us = (getpindex() * lm_optT) + gettindex(); 168 them = (us + 1) % (lm_optP * lm_optT); 169 170 ts->ts_id = us; 171 172 /* lock index asignment for us and them */ 173 ts->ts_us0 = (us * 4); 174 ts->ts_us1 = (us * 4) + 2; 175 if (us < nthreads - 1) { 176 /* straight-thru connection to them */ 177 ts->ts_them0 = (them * 4); 178 ts->ts_them1 = (them * 4) + 2; 179 } else { 180 /* cross-over connection to them */ 181 ts->ts_them0 = (them * 4) + 2; 182 ts->ts_them1 = (them * 4); 183 } 184 185 ts->ts_once = 1; 186 } 187 188 /* block their first move */ 189 e += block(ts->ts_them0); 190 191 return (e); 192 } 193 194 int 195 benchmark(void *tsd, result_t *res) 196 { 197 tsd_t *ts = (tsd_t *)tsd; 198 int i; 199 int e = 0; 200 201 /* wait to be unblocked (id == 0 will not block) */ 202 e += block(ts->ts_us0); 203 204 for (i = 0; i < lm_optB; i += 2) { 205 /* allow them to block us again */ 206 e += unblock(ts->ts_us0); 207 208 /* block their next + 1 move */ 209 e += block(ts->ts_them1); 210 211 /* unblock their next move */ 212 e += unblock(ts->ts_them0); 213 214 /* wait for them to unblock us */ 215 e += block(ts->ts_us1); 216 217 /* repeat with locks reversed */ 218 e += unblock(ts->ts_us1); 219 e += block(ts->ts_them0); 220 e += unblock(ts->ts_them1); 221 e += block(ts->ts_us0); 222 } 223 224 /* finish batch with nothing blocked */ 225 e += unblock(ts->ts_them0); 226 e += unblock(ts->ts_us0); 227 228 res->re_count = i; 229 res->re_errors = e; 230 231 return (0); 232 } 233