added writesize
[tridge/junkcode.git] / semspeed.c
1 /* quick test of semaphore speed */
2
3 /*
4
5 Results with the following defines:
6   #define NSEMS 20
7   #define NPROCS 60
8   #define NUMOPS 10000
9
10   OSF1 dominion.aquasoft.com.au V4.0 564 alpha (233 MHz)
11   fcntl: 132.814 secs
12   ipc: 13.5186 secs
13
14   Linux dominion.aquasoft.com.au 2.0.30 (alpha 233 MHz)
15   fcntl: 16.9473 secs
16   ipc: 61.9336 secs
17
18   Linux 2.1.57 on a P120
19   fcntl: 21.3006 secs
20   ipc: 93.9982 secs
21
22   Solaris 2.5 on a Ultra170
23   fcntl: 192.805 secs
24   ipc: 18.6859 secs
25
26   IRIX 6.4 on a Origin200
27   fcntl: 183.488 secs
28   ipc: 10.4431 secs
29
30   SunOS 4.1.3 on a 2 CPU sparc 10
31   fcntl: 198.239 secs
32   ipc: 150.026 secs
33
34   Solaris 2.5.1 on a 4 CPU SPARCsystem-600
35   fcntl: 312.025 secs
36   ipc: 24.5416 secs
37
38   Linux 2.1.131 on K6/200
39   fcntl: 8.27074 secs
40   ipc: 49.7771 secs
41
42   Linux 2.0.34 on P200
43   fcntl: 7.99596 secs
44   ipc: 52.3388 secs
45
46   AIX 4.2 on 2-proc RS6k with 233MHz processors
47   fcntl: 12.4272 secs
48   ipc: 5.41895 secs
49
50  */
51
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <fcntl.h>
55 #include <errno.h>
56 #include <unistd.h>
57 #include <sys/stat.h>
58 #include <sys/ipc.h>
59 #include <sys/sem.h>
60 #include <sys/time.h>
61 #ifdef HAVE_POSIX_SEM
62 #include <semaphore.h>
63 #endif
64
65 #define NSEMS 20
66 #define NPROCS 60
67 #define NUMOPS 10000
68
69 #define SEMAPHORE_KEY 0x569890
70 #define SHM_KEY 0x568698
71
72 static int fcntl_fd;
73 static int sem_id;
74 static int shm_id;
75 static int *shm_p;
76 static int mypid;
77
78 #ifdef HAVE_POSIX_SEM
79 static sem_t posix_sems[NSEMS];
80 #endif
81
82 static int state[NSEMS];          
83
84 #define BUFSIZE (1024)
85 static char buf1[BUFSIZE];
86 static char buf2[BUFSIZE];
87
88 #ifdef NO_SEMUN
89 union semun {
90         int val;
91         struct semid_ds *buf;
92         unsigned short *array;
93 };
94 #endif
95
96
97 static struct timeval tp1,tp2;
98
99 static void start_timer()
100 {
101         gettimeofday(&tp1,NULL);
102 }
103
104 static double end_timer()
105 {
106         gettimeofday(&tp2,NULL);
107         return((tp2.tv_sec - tp1.tv_sec) + 
108                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
109 }
110
111
112 /************************************************************************
113   USING FCNTL LOCKS 
114   ***********************************************************************/
115 void fcntl_setup(void)
116 {
117         fcntl_fd = open("fcntl.locks", O_RDWR | O_CREAT | O_TRUNC, 0600);
118         write(fcntl_fd, state, sizeof(state));
119 }
120
121 void fcntl_close(void)
122 {
123         unlink("fcntl.locks");
124 }
125
126 void fcntl_sem_lock(int i)
127 {
128         struct flock lock;
129         int ret;
130
131         lock.l_type = F_WRLCK;
132         lock.l_whence = SEEK_SET;
133         lock.l_start = i*sizeof(int);
134         lock.l_len = sizeof(int);
135         lock.l_pid = 0;
136
137         errno = 0;
138
139         if (fcntl(fcntl_fd, F_SETLKW, &lock) != 0) {
140                 perror("WRLCK");
141                 exit(1);
142         }
143 }
144
145 void fcntl_sem_unlock(int i)
146 {
147         struct flock lock;
148         int ret;
149
150         lock.l_type = F_UNLCK;
151         lock.l_whence = SEEK_SET;
152         lock.l_start = i*sizeof(int);
153         lock.l_len = sizeof(int);
154         lock.l_pid = 0;
155
156         errno = 0;
157
158         if (fcntl(fcntl_fd, F_SETLKW, &lock) != 0) {
159                 perror("WRLCK");
160                 exit(1);
161         }
162 }
163
164
165
166 /************************************************************************
167   USING SYSV IPC SEMAPHORES
168   ***********************************************************************/
169 void ipc_setup(void)
170 {
171         int i;
172         union semun su;
173
174         su.val = 1;
175
176         sem_id = semget(SEMAPHORE_KEY, NSEMS, 
177                         IPC_CREAT|IPC_EXCL|0600);
178         if (sem_id == -1) {
179                 sem_id = semget(SEMAPHORE_KEY, 0, 0);
180                 if (sem_id != -1) {
181                         semctl(sem_id, 0, IPC_RMID, su);
182                         sem_id = semget(SEMAPHORE_KEY, NSEMS, 
183                                         IPC_CREAT|IPC_EXCL|0600);
184                 }
185         }
186         if (sem_id == -1) {
187                 perror("semget");
188                 exit(1);
189         }
190
191         for (i=0;i<NSEMS;i++) {
192                 semctl(sem_id, i, SETVAL, su);
193         }
194
195         if (sem_id == -1) {
196                 perror("semget");
197                 exit(1);
198         }
199 }
200
201 void ipc_close(void)
202 {
203         union semun su;
204         su.val = 1;
205         semctl(sem_id, 0, IPC_RMID, su);
206 }
207
208
209 void ipc_change(int i, int op)
210 {
211         struct sembuf sb;
212         sb.sem_num = i;
213         sb.sem_op = op;
214         sb.sem_flg = 0;
215         if (semop(sem_id, &sb, 1)) {
216                 fprintf(stderr,"semop(%d,%d): ", i, op);
217                 perror("");
218                 exit(1);
219         }
220 }
221
222 void ipc_sem_lock(int i)
223 {
224         ipc_change(i, -1);
225 }
226
227 void ipc_sem_unlock(int i)
228 {
229         ipc_change(i, 1);
230 }
231
232
233 #ifdef HAVE_POSIX_SEM
234 /************************************************************************
235   USING POSIX semaphores
236   ***********************************************************************/
237 void posix_setup(void)
238 {
239         int i;
240
241         for (i=0;i<NSEMS;i++) {
242                 if (sem_init(&posix_sems[i], 1, 1) != 0) {
243                         fprintf(stderr,"failed to setup semaphore %d\n", i);
244                         break;
245                 }
246         }
247 }
248
249 void posix_close(void)
250 {
251         int i;
252
253         for (i=0;i<NSEMS;i++) {
254                 if (sem_close(&posix_sems[i]) != 0) {
255                         fprintf(stderr,"failed to close semaphore %d\n", i);
256                         break;
257                 }
258         }
259 }
260
261
262 void posix_lock(int i)
263 {
264         if (sem_wait(&posix_sems[i]) != 0) fprintf(stderr,"failed to get lock %d\n", i);
265 }
266
267 void posix_unlock(int i)
268 {
269         if (sem_post(&posix_sems[i]) != 0) fprintf(stderr,"failed to release lock %d\n", i);
270 }
271 #endif
272
273
274 void test_speed(char *s, void (*lock_fn)(int ), void (*unlock_fn)(int ))
275 {
276         int i, j, status;
277         pid_t pids[NPROCS];
278
279         for (i=0;i<NSEMS;i++) {
280                 lock_fn(i);
281         }
282
283         for (i=0;i<NPROCS;i++) {
284                 pids[i] = fork();
285                 if (pids[i] == 0) {
286                         mypid = getpid();
287                         srandom(mypid ^ time(NULL));
288                         for (j=0;j<NUMOPS;j++) {
289                                 unsigned sem = random() % NSEMS;
290
291                                 lock_fn(sem);
292                                 memcpy(buf2, buf1, sizeof(buf1));
293                                 unlock_fn(sem);
294                                 memcpy(buf1, buf2, sizeof(buf1));
295                         }
296                         exit(0);
297                 }
298         }
299
300         sleep(1);
301         
302         printf("%s: ", s);
303         fflush(stdout);
304
305         start_timer();
306
307         for (i=0;i<NSEMS;i++) {
308                 unlock_fn(i);
309         }
310
311         for (i=0;i<NPROCS;i++)
312                 waitpid(pids[i], &status, 0);
313
314         printf("%g secs\n", end_timer());
315 }
316
317 int main(int argc, char *argv[])
318 {
319         srandom(getpid() ^ time(NULL));
320
321         printf("NPROCS=%d NSEMS=%d NUMOPS=%d\n", NPROCS, NSEMS, NUMOPS);
322
323         
324         fcntl_setup();
325         test_speed("fcntl", fcntl_sem_lock, fcntl_sem_unlock);
326         fcntl_close();
327
328         ipc_setup();
329         test_speed("ipc", ipc_sem_lock, ipc_sem_unlock);
330         ipc_close();
331
332 #ifdef HAVE_POSIX_SEM
333         posix_setup();
334         test_speed("posix", posix_lock, posix_unlock);
335         posix_close();
336 #endif
337
338         return 0;
339 }