[dbench @ cvs-1:tridge-20041212143742-r0tjbd9yb1njroen]
[tridge/dbench.git] / dbench.c
1 /* 
2    Copyright (C) by Andrew Tridgell <tridge@samba.org> 1999, 2001
3    Copyright (C) 2001 by Martin Pool <mbp@samba.org>
4    
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 /* TODO: We could try allowing for different flavours of synchronous
21    operation: data sync and so on.  Linux apparently doesn't make any
22    distinction, however, and for practical purposes it probably
23    doesn't matter.  On NFSv4 it might be interesting, since the client
24    can choose what kind it wants for each OPEN operation. */
25
26 #include "dbench.h"
27
28 int sync_open = 0, sync_dirs = 0;
29 char *tcp_options = TCP_OPTIONS;
30 static int timelimit = 600, warmup;
31 static const char *directory = ".";
32 static char *loadfile = DATADIR "/client.txt";
33 static struct timeval tv_start;
34 static struct timeval tv_end;
35
36 #if HAVE_EA_SUPPORT
37 int ea_enable=0;
38 #endif
39
40 static FILE *open_loadfile(void)
41 {
42         FILE            *f;
43
44         if ((f = fopen(loadfile, "rt")) != NULL)
45                 return f;
46
47         fprintf(stderr,
48                 "dbench: error opening '%s': %s\n", loadfile,
49                 strerror(errno));
50
51         return NULL;
52 }
53
54
55 static struct child_struct *children;
56
57 static void sigcont(int sig)
58 {
59         (void)sig;
60 }
61
62 static void sig_alarm(int sig)
63 {
64         double total_bytes = 0;
65         int total_lines = 0;
66         int i;
67         int nprocs = children[0].nprocs;
68         int in_warmup = 0;
69         double t;
70         static int in_cleanup;
71
72         (void)sig;
73
74         for (i=0;i<nprocs;i++) {
75                 total_bytes += children[i].bytes - children[i].bytes_done_warmup;
76                 if (children[i].bytes == 0) {
77                         in_warmup = 1;
78                 }
79                 total_lines += children[i].line;
80         }
81
82         t = timeval_elapsed(&tv_start);
83
84         if (!in_warmup && warmup>0 && t > warmup) {
85                 tv_start = timeval_current();
86                 warmup = 0;
87                 for (i=0;i<nprocs;i++) {
88                         children[i].bytes_done_warmup = children[i].bytes;
89                 }
90                 goto next;
91         }
92         if (t < warmup) {
93                 in_warmup = 1;
94         } else if (!in_warmup && !in_cleanup && t > timelimit) {
95                 for (i=0;i<nprocs;i++) {
96                         children[i].done = 1;
97                 }
98                 tv_end = timeval_current();
99                 in_cleanup = 1;
100         }
101         if (t < 1) {
102                 goto next;
103         }
104
105         if (in_warmup) {
106                 printf("%4d  %8d  %7.2f MB/sec  warmup %3.0f sec   \n", 
107                        nprocs, total_lines/nprocs, 
108                        1.0e-6 * total_bytes / t, t);
109         } else if (in_cleanup) {
110                 printf("%4d  %8d  %7.2f MB/sec  cleanup %3.0f sec   \n", 
111                        nprocs, total_lines/nprocs, 
112                        1.0e-6 * total_bytes / t, t);
113         } else {
114                 printf("%4d  %8d  %7.2f MB/sec  execute %3.0f sec   \n", 
115                        nprocs, total_lines/nprocs, 
116                        1.0e-6 * total_bytes / t, t);
117         }
118
119         fflush(stdout);
120 next:
121         signal(SIGALRM, sig_alarm);
122         alarm(PRINT_FREQ);
123 }
124
125 /* this creates the specified number of child processes and runs fn()
126    in all of them */
127 static void create_procs(int nprocs, void (*fn)(struct child_struct *, const char *))
128 {
129         int i, status;
130         int synccount;
131         struct timeval tv;
132         FILE *load;
133
134         load = open_loadfile();
135         if (load == NULL) {
136                 exit(1);
137         }
138
139         signal(SIGCONT, sigcont);
140
141         synccount = 0;
142
143         if (nprocs < 1) {
144                 fprintf(stderr,
145                         "create %d procs?  you must be kidding.\n",
146                         nprocs);
147                 return;
148         }
149
150         children = shm_setup(sizeof(struct child_struct)*nprocs);
151         if (!children) {
152                 printf("Failed to setup shared memory\n");
153                 return;
154         }
155
156         memset(children, 0, sizeof(*children)*nprocs);
157
158         for (i=0;i<nprocs;i++) {
159                 children[i].id = i;
160                 children[i].nprocs = nprocs;
161                 children[i].cleanup = 0;
162                 children[i].directory = directory;
163         }
164
165         for (i=0;i<nprocs;i++) {
166                 if (fork() == 0) {
167                         setlinebuf(stdout);
168                         nb_setup(&children[i]);
169                         children[i].status = getpid();
170                         pause();
171                         fn(&children[i], loadfile);
172                         _exit(0);
173                 }
174         }
175
176         tv = timeval_current();
177         do {
178                 synccount = 0;
179                 for (i=0;i<nprocs;i++) {
180                         if (children[i].status) synccount++;
181                 }
182                 if (synccount == nprocs) break;
183                 usleep(100000);
184         } while (timeval_elapsed(&tv) < 30);
185
186         if (synccount != nprocs) {
187                 printf("FAILED TO START %d CLIENTS (started %d)\n", nprocs, synccount);
188                 return;
189         }
190
191         printf("%d clients started\n", nprocs);
192
193         kill(0, SIGCONT);
194
195         tv_start = timeval_current();
196
197         signal(SIGALRM, sig_alarm);
198         alarm(PRINT_FREQ);
199
200         for (i=0;i<nprocs;) {
201                 if (waitpid(0, &status, 0) == -1) continue;
202                 if (WEXITSTATUS(status) != 0) {
203                         printf("Child failed with status %d\n",
204                                WEXITSTATUS(status));
205                         exit(1);
206                 }
207                 i++;
208         }
209
210         alarm(0);
211         sig_alarm(SIGALRM);
212
213         printf("\n");
214 }
215
216
217 static void show_usage(void)
218 {
219         printf("usage: dbench [OPTIONS] nprocs\n" \
220                "usage: tbench [OPTIONS] nprocs <server>\n" \
221                "options:\n" \
222                "  -v               show version\n" \
223                "  -t timelimit     run time in seconds (default 600)\n" \
224                "  -D directory     base directory to run in\n" \
225                "  -c loadfile      set location of the loadfile\n" \
226                "  -s               synchronous file IO\n" \
227                "  -S               synchronous directories (mkdir, unlink...)\n" \
228                "  -x               enable EA support\n" \
229                "  -T options       set socket options for tbench\n");
230         exit(1);
231 }
232
233
234
235 static int process_opts(int argc, char **argv,
236                         int *nprocs)
237 {
238         int c;
239         extern int sync_open;
240         extern char *server;
241
242         while ((c = getopt(argc, argv, "vc:sST:t:xD:")) != -1) 
243                 switch (c) {
244                 case 'c':
245                         loadfile = optarg;
246                         break;
247                 case 's':
248                         sync_open = 1;
249                         break;
250                 case 'S':
251                         sync_dirs = 1;
252                         break;
253                 case 'T':
254                         tcp_options = optarg;
255                         break;
256                 case 't':
257                         timelimit = atoi(optarg);
258                         break;
259                 case 'D':
260                         directory = optarg;
261                         break;
262                 case 'v':
263                         exit(0);
264                         break;
265                 case 'x':
266 #if HAVE_EA_SUPPORT
267                         ea_enable = 1;
268 #else
269                         printf("EA suppport not compiled in\n");
270                         exit(1);
271 #endif
272                         break;
273                 case '?':
274                         if (isprint (optopt))
275                                 fprintf (stderr, "Unknown option `-%c'.\n", optopt);
276                         else
277                                 fprintf (stderr,
278                                          "Unknown option character `\\x%x'.\n",
279                                          optopt);
280                         return 0;
281                 default:
282                         abort ();
283                 }
284         
285         if (!argv[optind])
286                 return 0;
287         
288         *nprocs = atoi(argv[optind++]);
289
290         if (argv[optind])
291                 server = argv[optind++];
292
293         return 1;
294 }
295
296
297
298  int main(int argc, char *argv[])
299 {
300         int nprocs;
301         double total_bytes = 0;
302         double t;
303         int i;
304
305         printf("dbench version %s - Copyright Andrew Tridgell 1999-2004\n\n", VERSION);
306
307         if (!process_opts(argc, argv, &nprocs))
308                 show_usage();
309
310         warmup = timelimit / 5;
311
312         printf("Running for %d seconds with load '%s' and minimum warmup %d secs\n", 
313                timelimit, loadfile, warmup);
314
315         create_procs(nprocs, child_run);
316
317         for (i=0;i<nprocs;i++) {
318                 total_bytes += children[i].bytes - children[i].bytes_done_warmup;
319         }
320
321         t = timeval_elapsed2(&tv_start, &tv_end);
322
323         printf("Throughput %g MB/sec%s%s %d procs\n", 
324                1.0e-6 * total_bytes / t,
325                sync_open ? " (sync open)" : "",
326                sync_dirs ? " (sync dirs)" : "", nprocs);
327         return 0;
328 }