Jacks program for testing multiple concurrent reader scalability.
[xfstests-dev.git] / src / scaleread.c
1 /*
2  * Copyright (c) 2003-2004 Silicon Graphics, Inc.  All Rights Reserved.
3  * 
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  * 
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  * 
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  * 
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc., 59
21  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  * 
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  * 
26  * http://www.sgi.com 
27  * 
28  * For further information regarding this notice, see: 
29  * 
30  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31  */
32 /*
33  * Test scaling of multiple processes opening/reading
34  * a number of small files simultaneously.
35  *      - create <f> files
36  *      - fork <n> processes
37  *      - wait for all processes ready
38  *      - start all proceses at the same time
39  *      - each processes opens , read, closes each file
40  *      - option to resync each process at each file
41  *
42  *      test [-c cpus] [-b bytes] [-f files] [-v] [-s] [-S]
43  *                      OR
44  *      test -i [-b bytes] [-f files] 
45  */
46 #include <unistd.h>
47 #include <string.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <sys/wait.h>
53 #include <fcntl.h>
54 #include <stdlib.h>
55 #include <sys/ipc.h>
56 #include <sys/shm.h>
57
58 void do_initfiles(void);
59 void slave(int);
60
61 #define VPRINT(x...)    do { if(verbose) fprintf(x);} while(0)
62 #define perrorx(s) do {perror(s); exit(1);} while (0)
63
64 long bytes=8192;
65 int cpus=1;
66 int init=0;
67 int strided=0;
68 int files=1;
69 int blksize=512;
70 int syncstep=0;
71 int verbose=0;
72
73 typedef struct {
74         volatile long   go;
75         long            fill[15];
76         volatile long   rdy[512];
77 } share_t;
78
79 share_t *sharep;
80
81
82 int
83 runon(int cpu)
84 {
85 #ifdef sys_sched_setaffinity
86         unsigned long mask[8];
87         
88         if (cpu < 0 || cpu >= 512)
89                 return -1;
90         memset(mask, 0, sizeof(mask));
91         mask[cpu/64] |= 1UL<<(cpu&63);
92
93         if (syscall(sys_sched_setaffinity, 0, sizeof(mask), mask))
94                 return -1;
95 #endif
96         return 0;
97 }
98
99 long
100 scaled_atol(char *p)
101 {
102         long val;
103         char  *pe;
104
105         val = strtol(p, &pe, 0);
106         if (*pe == 'K' || *pe == 'k')
107                 val *= 1024L;
108         else if (*pe == 'M' || *pe == 'm')
109                 val *= 1024L*1024L;
110         else if (*pe == 'G' || *pe == 'g')
111                 val *= 1024L*1024L*1024L;
112         else if (*pe == 'p' || *pe == 'P')
113                 val *= getpagesize();
114         return val;
115 }
116
117
118 int
119 main(int argc, char** argv) {
120         int shmid;
121         static  char            optstr[] = "c:b:f:sSivH";
122         int                     notdone, stat, i, j, c, er=0;
123
124         opterr=1;
125         while ((c = getopt(argc, argv, optstr)) != EOF)
126                 switch (c) {
127                 case 'c':
128                         cpus = atoi(optarg);
129                         break;
130                 case 'b':
131                         bytes = scaled_atol(optarg);
132                         break;
133                 case 'f':
134                         files = atoi(optarg);
135                         break;
136                 case 'i':
137                         init++;
138                         break;
139                 case 's':
140                         syncstep++;
141                         break;
142                 case 'S':
143                         strided++;
144                         break;
145                 case 'v':
146                         verbose++;
147                         break;
148                 case '?':
149                         er = 1;
150                         break;
151                 }
152         if (er) {
153                 printf("usage: %s %s\n", argv[0], optstr);
154                 exit(1);
155         }
156
157
158         if ((shmid = shmget(IPC_PRIVATE, sizeof (share_t), IPC_CREAT|SHM_R|SHM_W))  == -1)
159                 perrorx("shmget failed");
160         sharep = (share_t*)shmat(shmid, (void*)0, SHM_R|SHM_W);
161         memset(sharep, -1, sizeof (share_t));
162
163         if (init) {
164                 do_initfiles();
165                 exit(0);
166         }
167         for (i=0; i<cpus; i++) {
168                 if (fork() == 0)
169                         slave(i);
170         }
171
172         for (i=0; i<files; i++) {
173                 VPRINT(stderr, "%d:", i);
174                 notdone = cpus;
175                 do {
176                         for (j=0; j<cpus; j++) {
177                                 if (sharep->rdy[j] == i) {
178                                         sharep->rdy[j] = -1;
179                                         VPRINT(stderr, " %d", j);
180                                         notdone--;
181                                 }
182                         }
183                 } while (notdone);
184                 VPRINT(stderr, "\n");
185                 sharep->go = i;
186                 if (!syncstep)
187                         break;
188         }
189         VPRINT(stderr, "\n");
190
191         while (wait(&stat)> 0)
192                 VPRINT(stderr, ".");
193         VPRINT(stderr, "\n");
194
195         exit(0);
196 }
197
198 void 
199 slave(int id)
200 {
201         int     i, fd, byte;
202         char    *buf, filename[32];
203
204         runon (id+1);
205         buf = malloc(blksize);
206         bzero(buf, blksize);
207         for (i=0; i<files; i++) {
208                 if (!i || syncstep) {
209                         sharep->rdy[id] = i;
210                         while(sharep->go != i);
211                 }
212                 sprintf(filename, "/tmp/tst.%d", (strided ? ((i + id) % files) : i));
213                 if ((fd = open (filename, O_RDONLY)) < 0) {
214                         perrorx(filename);
215                 }
216         
217                 for (byte=0; byte<bytes; byte+=blksize) {
218                         if (read (fd, buf, blksize) != blksize)
219                                 perrorx("read of file failed");
220                 }
221                 close(fd);
222         }
223         exit(0);
224 }
225
226 void
227 do_initfiles(void)
228 {
229         int     i, fd, byte;
230         char    *buf, filename[32];
231
232         buf = malloc(blksize);
233         bzero(buf, blksize);
234
235         for (i=0; i<files; i++) {
236                 sprintf(filename, "/tmp/tst.%d", i);
237                 unlink(filename);
238                 if ((fd = open (filename, O_RDWR|O_CREAT, 0644)) < 0)
239                         perrorx(filename);
240         
241                 for (byte=0; byte<bytes; byte+=blksize) {
242                         if (write (fd, buf, blksize) != blksize)
243                                 perrorx("write of file failed");
244                 }
245                 close(fd);
246         }
247         sync();
248 }
249
250