9a3b91c18b6b75366ddf6a52d628e46aa2855455
[tridge/dbench.git] / child.c
1 /* 
2    dbench version 3
3
4    Copyright (C) Andrew Tridgell 1999-2004
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /* This file links against either fileio.c to do operations against a
21    local filesystem (making dbench), or sockio.c to issue SMB-like
22    command packets over a socket (making tbench).
23
24    So, the pattern of operations and the control structure is the same
25    for both benchmarks, but the operations performed are different.
26 */
27
28 #include "dbench.h"
29
30 #define ival(s) strtol(s, NULL, 0)
31
32 static void nb_target_rate(struct child_struct *child, double rate)
33 {
34         double tdelay;
35
36         if (child->rate.last_bytes == 0) {
37                 child->rate.last_bytes = child->bytes;
38                 child->rate.last_time = timeval_current();
39                 return;
40         }
41
42         if (rate != 0) {
43                 tdelay = (child->bytes - child->rate.last_bytes)/(1.0e6*rate) - 
44                         timeval_elapsed(&child->rate.last_time);
45         } else {
46                 tdelay = - timeval_elapsed(&child->rate.last_time);
47         }
48         if (tdelay > 0 && rate != 0) {
49                 msleep(tdelay*1000);
50         } else {
51                 child->max_latency = MAX(child->max_latency, -tdelay);
52         }
53
54         child->rate.last_time = timeval_current();
55         child->rate.last_bytes = child->bytes;
56 }
57
58 static void nb_time_reset(struct child_struct *child)
59 {
60         child->starttime = timeval_current();   
61         memset(&child->rate, 0, sizeof(child->rate));
62 }
63
64 static void nb_time_delay(struct child_struct *child, double targett)
65 {
66         double elapsed = timeval_elapsed(&child->starttime);
67         if (targett > elapsed) {
68                 msleep(1000*(targett - elapsed));
69         } else if (elapsed - targett > child->max_latency) {
70                 child->max_latency = MAX(elapsed - targett, child->max_latency);
71         }
72 }
73
74 static void finish_op(struct child_struct *child, struct op *op)
75 {
76         double t = timeval_elapsed(&child->lasttime);
77         op->count++;
78         op->total_time += t;
79         if (t > op->max_latency) {
80                 op->max_latency = t;
81         }
82 }
83
84 #define OP_LATENCY(opname) finish_op(child, &child->op.op_ ## opname)
85
86 /*
87   one child operation
88  */
89 static void child_op(struct child_struct *child, char **params, 
90                      const char *fname, const char *fname2, const char *status)
91 {
92         child->lasttime = timeval_current();
93
94         if (!strcmp(params[0],"NTCreateX")) {
95                 if (nb_ops.createx) {
96                         nb_ops.createx(child, fname, ival(params[2]), ival(params[3]), 
97                                    ival(params[4]), status);
98                         OP_LATENCY(NTCreateX);
99                 } else {
100                         printf("Operation NTCREATEX is not supported\n");
101                 }
102         } else if (!strcmp(params[0],"Close")) {
103                 if (nb_ops.close) {
104                         nb_ops.close(child, ival(params[1]), status);
105                         OP_LATENCY(Close);
106                 } else {
107                         printf("Operation CLOSE is not supported\n");
108                 }
109         } else if (!strcmp(params[0],"Rename")) {
110                 if (nb_ops.rename) {
111                         nb_ops.rename(child, fname, fname2, status);
112                         OP_LATENCY(Rename);
113                 } else {
114                         printf("Operation RENAME is not supported\n");
115                 }
116         } else if (!strcmp(params[0],"Unlink")) {
117                 if (nb_ops.unlink) {
118                         nb_ops.unlink(child, fname, ival(params[2]), status);
119                         OP_LATENCY(Unlink);
120                 } else {
121                         printf("Operation UNLINK is not supported\n");
122                 }
123         } else if (!strcmp(params[0],"Deltree")) {
124                 if (nb_ops.deltree) {
125                         nb_ops.deltree(child, fname);
126                         OP_LATENCY(Deltree);
127                 } else {
128                         printf("Operation DELTREE is not supported\n");
129                 }
130         } else if (!strcmp(params[0],"Rmdir")) {
131                 if (nb_ops.rmdir) {
132                         nb_ops.rmdir(child, fname, status);
133                         OP_LATENCY(Rmdir);
134                 } else {
135                         printf("Operation RMDIR is not supported\n");
136                 }
137         } else if (!strcmp(params[0],"Mkdir")) {
138                 if (nb_ops.mkdir) {
139                         nb_ops.mkdir(child, fname, status);
140                         OP_LATENCY(Mkdir);
141                 } else {
142                         printf("Operation MKDIR is not supported\n");
143                 }
144         } else if (!strcmp(params[0],"QUERY_PATH_INFORMATION")) {
145                 if (nb_ops.qpathinfo) {
146                         nb_ops.qpathinfo(child, fname, ival(params[2]), status);
147                         OP_LATENCY(Qpathinfo);
148                 } else {
149                         printf("Operation QUERY_PATH_INFORMATION is not supported\n");
150                 }
151         } else if (!strcmp(params[0],"QUERY_FILE_INFORMATION")) {
152                 if (nb_ops.qfileinfo) {
153                         nb_ops.qfileinfo(child, ival(params[1]), ival(params[2]), status);
154                         OP_LATENCY(Qfileinfo);
155                 } else {
156                         printf("Operation QUERY_FILE_INFORMATION is not supported\n");
157                 }
158         } else if (!strcmp(params[0],"QUERY_FS_INFORMATION")) {
159                 if (nb_ops.qfsinfo) {
160                         nb_ops.qfsinfo(child, ival(params[1]), status);
161                         OP_LATENCY(Qfsinfo);
162                 } else {
163                         printf("Operation QUERY_FS_INFORMATION is not supported\n");
164                 }
165         } else if (!strcmp(params[0],"SET_FILE_INFORMATION")) {
166                 if (nb_ops.sfileinfo) {
167                         nb_ops.sfileinfo(child, ival(params[1]), ival(params[2]), status);
168                         OP_LATENCY(Sfileinfo);
169                 } else {
170                         printf("Operation SET_FILE_INFORMATION is not supported\n");
171                 }
172         } else if (!strcmp(params[0],"FIND_FIRST")) {
173                 if (nb_ops.findfirst) {
174                         nb_ops.findfirst(child, fname, ival(params[2]), 
175                                      ival(params[3]), ival(params[4]), status);
176                         OP_LATENCY(Find);
177                 } else {
178                         printf("Operation FINDFIRST is not supported\n");
179                 }
180         } else if (!strcmp(params[0],"WriteX")) {
181                 if (nb_ops.writex) {
182                         nb_ops.writex(child, ival(params[1]), 
183                                   ival(params[2]), ival(params[3]), ival(params[4]),
184                                   status);
185                         OP_LATENCY(WriteX);
186                 } else {
187                         printf("Operation WRITEX is not supported\n");
188                 }
189         } else if (!strcmp(params[0],"LockX")) {
190                 if (nb_ops.lockx) {
191                         nb_ops.lockx(child, ival(params[1]), 
192                                  ival(params[2]), ival(params[3]), status);
193                         OP_LATENCY(LockX);
194                 } else {
195                         printf("Operation LOCKX is not supported\n");
196                 }
197         } else if (!strcmp(params[0],"UnlockX")) {
198                 if (nb_ops.unlockx) {
199                         nb_ops.unlockx(child, ival(params[1]), 
200                                    ival(params[2]), ival(params[3]), status);
201                         OP_LATENCY(UnlockX);
202                 } else {
203                         printf("Operation UNLOCKX is not supported\n");
204                 }
205         } else if (!strcmp(params[0],"ReadX")) {
206                 if (nb_ops.readx) {
207                         nb_ops.readx(child, ival(params[1]), 
208                                  ival(params[2]), ival(params[3]), ival(params[4]),
209                                  status);
210                         OP_LATENCY(ReadX);
211                 } else {
212                         printf("Operation READX is not supported\n");
213                 }
214         } else if (!strcmp(params[0],"Flush")) {
215                 if (nb_ops.flush) {
216                         nb_ops.flush(child, ival(params[1]), status);
217                         OP_LATENCY(Flush);
218                 } else {
219                         printf("Operation FLUSH is not supported\n");
220                 }
221         } else if (!strcmp(params[0],"GETATTR3")) {
222                 if (nb_ops.getattr3) {
223                         nb_ops.getattr3(child, fname, status);
224                         OP_LATENCY(GETATTR3);
225                 } else {
226                         printf("Operation GETATTR3 is not supported\n");
227                 }
228         } else if (!strcmp(params[0],"LOOKUP3")) {
229                 if (nb_ops.getattr3) {
230                         nb_ops.lookup3(child, fname, status);
231                         OP_LATENCY(LOOKUP3);
232                 } else {
233                         printf("Operation LOOKUP3 is not supported\n");
234                 }
235         } else if (!strcmp(params[0],"CREATE3")) {
236                 if (nb_ops.create3) {
237                         nb_ops.create3(child, fname, status);
238                         OP_LATENCY(CREATE3);
239                 } else {
240                         printf("Operation CREATE3 is not supported\n");
241                 }
242         } else if (!strcmp(params[0],"WRITE3")) {
243                 if (nb_ops.write3) {
244                         nb_ops.write3(child, fname, ival(params[2]),
245                                 ival(params[3]),
246                                 ival(params[4]), status);
247                         OP_LATENCY(WRITE3);
248                 } else {
249                         printf("Operation WRITE3 is not supported\n");
250                 }
251         } else if (!strcmp(params[0],"COMMIT3")) {
252                 if (nb_ops.commit3) {
253                         nb_ops.commit3(child, fname, status);
254                         OP_LATENCY(COMMIT3);
255                 } else {
256                         printf("Operation COMMIT3 is not supported\n");
257                 }
258         } else if (!strcmp(params[0],"READ3")) {
259                 if (nb_ops.read3) {
260                         nb_ops.read3(child, fname, ival(params[2]),
261                                 ival(params[3]), status);
262                         OP_LATENCY(READ3);
263                 } else {
264                         printf("Operation READ3 is not supported\n");
265                 }
266         } else if (!strcmp(params[0],"ACCESS3")) {
267                 if (nb_ops.access3) {
268                         nb_ops.access3(child, fname, ival(params[2]),
269                                 ival(params[3]), status);
270                         OP_LATENCY(ACCESS3);
271                 } else {
272                         printf("Operation ACCESS3 is not supported\n");
273                 }
274         } else if (!strcmp(params[0],"MKDIR3")) {
275                 if (nb_ops.mkdir3) {
276                         nb_ops.mkdir3(child, fname, status);
277                         OP_LATENCY(MKDIR3);
278                 } else {
279                         printf("Operation MKDIR3 is not supported\n");
280                 }
281         } else if (!strcmp(params[0],"RMDIR3")) {
282                 if (nb_ops.rmdir3) {
283                         nb_ops.rmdir3(child, fname, status);
284                         OP_LATENCY(RMDIR3);
285                 } else {
286                         printf("Operation RMDIR3 is not supported\n");
287                 }
288         } else if (!strcmp(params[0],"FSSTAT3")) {
289                 if (nb_ops.fsstat3) {
290                         nb_ops.fsstat3(child, status);
291                         OP_LATENCY(FSSTAT3);
292                 } else {
293                         printf("Operation FSSTAT3 is not supported\n");
294                 }
295         } else if (!strcmp(params[0],"FSINFO3")) {
296                 if (nb_ops.fsinfo3) {
297                         nb_ops.fsinfo3(child, status);
298                         OP_LATENCY(FSINFO3);
299                 } else {
300                         printf("Operation FSINFO3 is not supported\n");
301                 }
302         } else if (!strcmp(params[0],"SYMLINK3")) {
303                 if (nb_ops.symlink3) {
304                         nb_ops.symlink3(child, fname, fname2, status);
305                         OP_LATENCY(SYMLINK3);
306                 } else {
307                         printf("Operation SYMLINK3 is not supported\n");
308                 }
309         } else if (!strcmp(params[0],"LINK3")) {
310                 if (nb_ops.link3) {
311                         nb_ops.link3(child, fname, fname2, status);
312                         OP_LATENCY(LINK3);
313                 } else {
314                         printf("Operation LINK3 is not supported\n");
315                 }
316         } else if (!strcmp(params[0],"REMOVE3")) {
317                 if (nb_ops.remove3) {
318                         nb_ops.remove3(child, fname, status);
319                         OP_LATENCY(REMOVE3);
320                 } else {
321                         printf("Operation REMOVE3 is not supported\n");
322                 }
323         } else if (!strcmp(params[0],"READDIRPLUS3")) {
324                 if (nb_ops.readdirplus3) {
325                         nb_ops.readdirplus3(child, fname, status);
326                         OP_LATENCY(READDIRPLUS3);
327                 } else {
328                         printf("Operation READDIRPLUS3 is not supported\n");
329                 }
330         } else if (!strcmp(params[0],"Sleep")) {
331                 nb_sleep(child, ival(params[1]), status);
332         } else {
333                 printf("[%d] Unknown operation %s in pid %d\n", 
334                        child->line, params[0], getpid());
335         }
336 }
337
338
339 /* run a test that simulates an approximate netbench client load */
340 void child_run(struct child_struct *child0, const char *loadfile)
341 {
342         int i;
343         char line[1024], fname[1024], fname2[1024];
344         char **sparams, **params;
345         char *p;
346         const char *status;
347         FILE *f;
348         pid_t parent = getppid();
349         double targett;
350         struct child_struct *child;
351
352         for (child=child0;child<child0+options.clients_per_process;child++) {
353                 child->line = 0;
354                 asprintf(&child->cname,"client%d", child->id);
355         }
356
357         sparams = calloc(20, sizeof(char *));
358         for (i=0;i<20;i++) {
359                 sparams[i] = malloc(100);
360         }
361
362         f = fopen(loadfile, "r");
363         if (f == NULL) {
364                 perror(loadfile);
365                 exit(1);
366         }
367
368 again:
369         for (child=child0;child<child0+options.clients_per_process;child++) {
370                 nb_time_reset(child);
371         }
372
373         while (fgets(line, sizeof(line)-1, f)) {
374                 params = sparams;
375
376                 if (kill(parent, 0) == -1) {
377                         exit(1);
378                 }
379
380                 for (child=child0;child<child0+options.clients_per_process;child++) {
381                         if (child->done) goto done;
382                         child->line++;
383                 }
384
385                 line[strlen(line)-1] = 0;
386
387                 all_string_sub(line,"\\", "/");
388                 all_string_sub(line," /", " ");
389                 
390                 p = line;
391                 for (i=0; 
392                      i<19 && next_token(&p, params[i], " ");
393                      i++) ;
394
395                 params[i][0] = 0;
396
397                 if (i < 2 || params[0][0] == '#') continue;
398
399                 if (!strncmp(params[0],"SMB", 3)) {
400                         printf("ERROR: You are using a dbench 1 load file\n");
401                         exit(1);
402                 }
403
404                 if (i > 0 && isdigit(params[0][0])) {
405                         targett = strtod(params[0], NULL);
406                         params++;
407                         i--;
408                 } else {
409                         targett = 0.0;
410                 }
411
412                 if (strncmp(params[i-1], "NT_STATUS_", 10) != 0 &&
413                     strncmp(params[i-1], "0x", 2) != 0) {
414                         printf("Badly formed status at line %d\n", child->line);
415                         continue;
416                 }
417
418                 status = params[i-1];
419                 
420                 for (child=child0;child<child0+options.clients_per_process;child++) {
421                         fname[0] = 0;
422                         fname2[0] = 0;
423
424                         if (i>1 && params[1][0] == '/') {
425                                 snprintf(fname, sizeof(fname), "%s%s", child->directory, params[1]);
426                                 all_string_sub(fname,"client1", child->cname);
427                         }
428                         if (i>2 && params[2][0] == '/') {
429                                 snprintf(fname2, sizeof(fname2), "%s%s", child->directory, params[2]);
430                                 all_string_sub(fname2,"client1", child->cname);
431                         }
432
433                         if (options.targetrate != 0 || targett == 0.0) {
434                                 nb_target_rate(child, options.targetrate);
435                         } else {
436                                 nb_time_delay(child, targett);
437                         }
438                         child_op(child, params, fname, fname2, status);
439                 }
440         }
441
442         rewind(f);
443         goto again;
444
445 done:
446         fclose(f);
447         for (child=child0;child<child0+options.clients_per_process;child++) {
448                 child->cleanup = 1;
449                 fflush(stdout);
450                 if (!options.skip_cleanup) {
451                         nb_ops.cleanup(child);
452                 }
453                 child->cleanup_finished = 1;
454         }
455 }