confirm results
[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   Linux 2.6.27 on Core-2-duo T61 thinkpad
51   fcntl: 0.718363 secs
52   ipc: 2.12952 secs
53
54   Linux 2.6.27 on Core-2-quad
55   fcntl: 0.718363 secs
56   ipc: 2.12952 secs
57   
58  */
59
60 #include <stdlib.h>
61 #include <stdio.h>
62 #include <fcntl.h>
63 #include <errno.h>
64 #include <unistd.h>
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #include <sys/ipc.h>
68 #include <sys/sem.h>
69 #include <sys/time.h>
70 #ifdef HAVE_POSIX_SEM
71 #include <semaphore.h>
72 #endif
73
74 #define NSEMS 20
75 #define NPROCS 60
76 #define NUMOPS 10000
77
78 #define SEMAPHORE_KEY 0x569890
79 #define SHM_KEY 0x568698
80
81 static int fcntl_fd;
82 static int sem_id;
83 static int shm_id;
84 static int *shm_p;
85 static int mypid;
86
87 #ifdef HAVE_POSIX_SEM
88 static sem_t posix_sems[NSEMS];
89 #endif
90
91 static int state[NSEMS];          
92
93 #define BUFSIZE (1024)
94 static char buf1[BUFSIZE];
95 static char buf2[BUFSIZE];
96
97 #ifdef NO_SEMUN
98 union semun {
99         int val;
100         struct semid_ds *buf;
101         unsigned short *array;
102 };
103 #endif
104
105
106 static struct timeval tp1,tp2;
107
108 static void start_timer()
109 {
110         gettimeofday(&tp1,NULL);
111 }
112
113 static double end_timer()
114 {
115         gettimeofday(&tp2,NULL);
116         return((tp2.tv_sec - tp1.tv_sec) + 
117                (tp2.tv_usec - tp1.tv_usec)*1.0e-6);
118 }
119
120
121 /************************************************************************
122   USING FCNTL LOCKS 
123   ***********************************************************************/
124 void fcntl_setup(void)
125 {
126         fcntl_fd = open("fcntl.locks", O_RDWR | O_CREAT | O_TRUNC, 0600);
127         write(fcntl_fd, state, sizeof(state));
128 }
129
130 void fcntl_close(void)
131 {
132         unlink("fcntl.locks");
133 }
134
135 void fcntl_sem_lock(int i)
136 {
137         struct flock lock;
138         int ret;
139
140         lock.l_type = F_WRLCK;
141         lock.l_whence = SEEK_SET;
142         lock.l_start = i*sizeof(int);
143         lock.l_len = sizeof(int);
144         lock.l_pid = 0;
145
146         errno = 0;
147
148         if (fcntl(fcntl_fd, F_SETLKW, &lock) != 0) {
149                 perror("WRLCK");
150                 exit(1);
151         }
152 }
153
154 void fcntl_sem_unlock(int i)
155 {
156         struct flock lock;
157         int ret;
158
159         lock.l_type = F_UNLCK;
160         lock.l_whence = SEEK_SET;
161         lock.l_start = i*sizeof(int);
162         lock.l_len = sizeof(int);
163         lock.l_pid = 0;
164
165         errno = 0;
166
167         if (fcntl(fcntl_fd, F_SETLKW, &lock) != 0) {
168                 perror("WRLCK");
169                 exit(1);
170         }
171 }
172
173
174
175 /************************************************************************
176   USING SYSV IPC SEMAPHORES
177   ***********************************************************************/
178 void ipc_setup(void)
179 {
180         int i;
181         union semun su;
182
183         su.val = 1;
184
185         sem_id = semget(SEMAPHORE_KEY, NSEMS, 
186                         IPC_CREAT|IPC_EXCL|0600);
187         if (sem_id == -1) {
188                 sem_id = semget(SEMAPHORE_KEY, 0, 0);
189                 if (sem_id != -1) {
190                         semctl(sem_id, 0, IPC_RMID, su);
191                         sem_id = semget(SEMAPHORE_KEY, NSEMS, 
192                                         IPC_CREAT|IPC_EXCL|0600);
193                 }
194         }
195         if (sem_id == -1) {
196                 perror("semget");
197                 exit(1);
198         }
199
200         for (i=0;i<NSEMS;i++) {
201                 semctl(sem_id, i, SETVAL, su);
202         }
203
204         if (sem_id == -1) {
205                 perror("semget");
206                 exit(1);
207         }
208 }
209
210 void ipc_close(void)
211 {
212         union semun su;
213         su.val = 1;
214         semctl(sem_id, 0, IPC_RMID, su);
215 }
216
217
218 void ipc_change(int i, int op)
219 {
220         struct sembuf sb;
221         sb.sem_num = i;
222         sb.sem_op = op;
223         sb.sem_flg = 0;
224         if (semop(sem_id, &sb, 1)) {
225                 fprintf(stderr,"semop(%d,%d): ", i, op);
226                 perror("");
227                 exit(1);
228         }
229 }
230
231 void ipc_sem_lock(int i)
232 {
233         ipc_change(i, -1);
234 }
235
236 void ipc_sem_unlock(int i)
237 {
238         ipc_change(i, 1);
239 }
240
241
242 #ifdef HAVE_POSIX_SEM
243 /************************************************************************
244   USING POSIX semaphores
245   ***********************************************************************/
246 void posix_setup(void)
247 {
248         int i;
249
250         for (i=0;i<NSEMS;i++) {
251                 if (sem_init(&posix_sems[i], 1, 1) != 0) {
252                         fprintf(stderr,"failed to setup semaphore %d\n", i);
253                         break;
254                 }
255         }
256 }
257
258 void posix_close(void)
259 {
260         int i;
261
262         for (i=0;i<NSEMS;i++) {
263                 if (sem_close(&posix_sems[i]) != 0) {
264                         fprintf(stderr,"failed to close semaphore %d\n", i);
265                         break;
266                 }
267         }
268 }
269
270
271 void posix_lock(int i)
272 {
273         if (sem_wait(&posix_sems[i]) != 0) fprintf(stderr,"failed to get lock %d\n", i);
274 }
275
276 void posix_unlock(int i)
277 {
278         if (sem_post(&posix_sems[i]) != 0) fprintf(stderr,"failed to release lock %d\n", i);
279 }
280 #endif
281
282
283 void test_speed(char *s, void (*lock_fn)(int ), void (*unlock_fn)(int ))
284 {
285         int i, j, status;
286         pid_t pids[NPROCS];
287
288         for (i=0;i<NSEMS;i++) {
289                 lock_fn(i);
290         }
291
292         for (i=0;i<NPROCS;i++) {
293                 pids[i] = fork();
294                 if (pids[i] == 0) {
295                         mypid = getpid();
296                         srandom(mypid ^ time(NULL));
297                         for (j=0;j<NUMOPS;j++) {
298                                 unsigned sem = random() % NSEMS;
299
300                                 lock_fn(sem);
301                                 memcpy(buf2, buf1, sizeof(buf1));
302                                 unlock_fn(sem);
303                                 memcpy(buf1, buf2, sizeof(buf1));
304                         }
305                         exit(0);
306                 }
307         }
308
309         sleep(1);
310         
311         printf("%s: ", s);
312         fflush(stdout);
313
314         start_timer();
315
316         for (i=0;i<NSEMS;i++) {
317                 unlock_fn(i);
318         }
319
320         for (i=0;i<NPROCS;i++)
321                 waitpid(pids[i], &status, 0);
322
323         printf("%g secs\n", end_timer());
324 }
325
326 int main(int argc, char *argv[])
327 {
328         srandom(getpid() ^ time(NULL));
329
330         printf("NPROCS=%d NSEMS=%d NUMOPS=%d\n", NPROCS, NSEMS, NUMOPS);
331
332         
333         fcntl_setup();
334         test_speed("fcntl", fcntl_sem_lock, fcntl_sem_unlock);
335         fcntl_close();
336
337         ipc_setup();
338         test_speed("ipc", ipc_sem_lock, ipc_sem_unlock);
339         ipc_close();
340
341 #ifdef HAVE_POSIX_SEM
342         posix_setup();
343         test_speed("posix", posix_lock, posix_unlock);
344         posix_close();
345 #endif
346
347         return 0;
348 }