Merge branch 'v4-0-test' into v4-0-gmake3
[metze/samba/wip.git] / source4 / torture / nbench / nbench.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester - NBENCH test
4    Copyright (C) Andrew Tridgell 1997-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 #include "includes.h"
21 #include "libcli/libcli.h"
22 #include "torture/util.h"
23 #include "torture/smbtorture.h"
24 #include "system/filesys.h"
25 #include "system/locale.h"
26 #include "pstring.h"
27
28 #include "torture/nbench/proto.h"
29
30 int nbench_line_count = 0;
31 static int timelimit = 600;
32 static int warmup;
33 static const char *loadfile;
34 static int read_only;
35
36 #define ival(s) strtoll(s, NULL, 0)
37
38 static unsigned long nb_max_retries;
39
40 #define NB_RETRY(op) \
41         for (n=0;n<=nb_max_retries && !op;n++) do_reconnect(&cli, tctx, client)
42
43 static void do_reconnect(struct smbcli_state **cli, struct torture_context *tctx, int client)
44 {
45         int n;
46         printf("[%d] Reconnecting client %d\n", nbench_line_count, client);
47         for (n=0;n<nb_max_retries;n++) {
48                 if (nb_reconnect(cli, tctx, client)) {
49                         printf("[%d] Reconnected client %d\n", nbench_line_count, client);
50                         return;
51                 }
52         }
53         printf("[%d] Failed to reconnect client %d\n", nbench_line_count, client);
54         nb_exit(1);
55 }
56
57 /* run a test that simulates an approximate netbench client load */
58 static bool run_netbench(struct torture_context *tctx, struct smbcli_state *cli, int client)
59 {
60         int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
61         int i;
62         pstring line;
63         char *cname;
64         FILE *f;
65         bool correct = true;
66         double target_rate = torture_setting_double(tctx, "targetrate", 0);     
67         int n;
68
69         if (target_rate != 0 && client == 0) {
70                 printf("Targetting %.4f MByte/sec\n", target_rate);
71         }
72
73         nb_setup(cli, client);
74
75         if (torture_nprocs == 1) {
76                 if (!read_only) {
77                         NB_RETRY(torture_setup_dir(cli, "\\clients"));
78                 }
79         }
80
81         asprintf(&cname, "client%d", client+1);
82
83         f = fopen(loadfile, "r");
84
85         if (!f) {
86                 perror(loadfile);
87                 return false;
88         }
89
90 again:
91         nbio_time_reset();
92
93         while (fgets(line, sizeof(line)-1, f)) {
94                 NTSTATUS status;
95                 const char **params0, **params;
96
97                 nbench_line_count++;
98
99                 line[strlen(line)-1] = 0;
100
101                 all_string_sub(line,"client1", cname, sizeof(line));
102                 
103                 params = params0 = str_list_make_shell(NULL, line, " ");
104                 i = str_list_length(params);
105
106                 if (i > 0 && isdigit(params[0][0])) {
107                         double targett = strtod(params[0], NULL);
108                         if (target_rate != 0) {
109                                 nbio_target_rate(target_rate);
110                         } else {
111                                 nbio_time_delay(targett);
112                         }
113                         params++;
114                         i--;
115                 } else if (target_rate != 0) {
116                         nbio_target_rate(target_rate);
117                 }
118
119                 if (i < 2 || params[0][0] == '#') continue;
120
121                 if (!strncmp(params[0],"SMB", 3)) {
122                         printf("ERROR: You are using a dbench 1 load file\n");
123                         nb_exit(1);
124                 }
125
126                 if (strncmp(params[i-1], "NT_STATUS_", 10) != 0 &&
127                     strncmp(params[i-1], "0x", 2) != 0) {
128                         printf("Badly formed status at line %d\n", nbench_line_count);
129                         talloc_free(params);
130                         continue;
131                 }
132
133                 /* accept numeric or string status codes */
134                 if (strncmp(params[i-1], "0x", 2) == 0) {
135                         status = NT_STATUS(strtoul(params[i-1], NULL, 16));
136                 } else {
137                         status = nt_status_string_to_code(params[i-1]);
138                 }
139
140                 DEBUG(9,("run_netbench(%d): %s %s\n", client, params[0], params[1]));
141
142                 if (!strcmp(params[0],"NTCreateX")) {
143                         NB_RETRY(nb_createx(params[1], ival(params[2]), ival(params[3]), 
144                                             ival(params[4]), status));
145                 } else if (!strcmp(params[0],"Close")) {
146                         NB_RETRY(nb_close(ival(params[1]), status));
147                 } else if (!read_only && !strcmp(params[0],"Rename")) {
148                         NB_RETRY(nb_rename(params[1], params[2], status, n>0));
149                 } else if (!read_only && !strcmp(params[0],"Unlink")) {
150                         NB_RETRY(nb_unlink(params[1], ival(params[2]), status, n>0));
151                 } else if (!read_only && !strcmp(params[0],"Deltree")) {
152                         NB_RETRY(nb_deltree(params[1], n>0));
153                 } else if (!read_only && !strcmp(params[0],"Rmdir")) {
154                         NB_RETRY(nb_rmdir(params[1], status, n>0));
155                 } else if (!read_only && !strcmp(params[0],"Mkdir")) {
156                         NB_RETRY(nb_mkdir(params[1], status, n>0));
157                 } else if (!strcmp(params[0],"QUERY_PATH_INFORMATION")) {
158                         NB_RETRY(nb_qpathinfo(params[1], ival(params[2]), status));
159                 } else if (!strcmp(params[0],"QUERY_FILE_INFORMATION")) {
160                         NB_RETRY(nb_qfileinfo(ival(params[1]), ival(params[2]), status));
161                 } else if (!strcmp(params[0],"QUERY_FS_INFORMATION")) {
162                         NB_RETRY(nb_qfsinfo(ival(params[1]), status));
163                 } else if (!read_only && !strcmp(params[0],"SET_FILE_INFORMATION")) {
164                         NB_RETRY(nb_sfileinfo(ival(params[1]), ival(params[2]), status));
165                 } else if (!strcmp(params[0],"FIND_FIRST")) {
166                         NB_RETRY(nb_findfirst(params[1], ival(params[2]), 
167                                               ival(params[3]), ival(params[4]), status));
168                 } else if (!read_only && !strcmp(params[0],"WriteX")) {
169                         NB_RETRY(nb_writex(ival(params[1]), 
170                                            ival(params[2]), ival(params[3]), ival(params[4]),
171                                            status));
172                 } else if (!read_only && !strcmp(params[0],"Write")) {
173                         NB_RETRY(nb_write(ival(params[1]), 
174                                           ival(params[2]), ival(params[3]), ival(params[4]),
175                                           status));
176                 } else if (!strcmp(params[0],"LockX")) {
177                         NB_RETRY(nb_lockx(ival(params[1]), 
178                                           ival(params[2]), ival(params[3]), status));
179                 } else if (!strcmp(params[0],"UnlockX")) {
180                         NB_RETRY(nb_unlockx(ival(params[1]), 
181                                             ival(params[2]), ival(params[3]), status));
182                 } else if (!strcmp(params[0],"ReadX")) {
183                         NB_RETRY(nb_readx(ival(params[1]), 
184                                           ival(params[2]), ival(params[3]), ival(params[4]),
185                                           status));
186                 } else if (!strcmp(params[0],"Flush")) {
187                         NB_RETRY(nb_flush(ival(params[1]), status));
188                 } else if (!strcmp(params[0],"Sleep")) {
189                         nb_sleep(ival(params[1]), status);
190                 } else {
191                         printf("[%d] Unknown operation %s\n", nbench_line_count, params[0]);
192                 }
193
194                 if (n > nb_max_retries) {
195                         printf("Maximum reconnect retries reached for op '%s'\n", params[0]);
196                         nb_exit(1);
197                 }
198
199                 talloc_free(params0);
200                 
201                 if (nb_tick()) goto done;
202         }
203
204         rewind(f);
205         goto again;
206
207 done:
208         fclose(f);
209
210         if (!read_only && torture_nprocs == 1) {
211                 smbcli_deltree(cli->tree, "\\clients");
212         }
213         if (!torture_close_connection(cli)) {
214                 correct = false;
215         }
216         
217         return correct;
218 }
219
220
221 /* run a test that simulates an approximate netbench client load */
222 bool torture_nbench(struct torture_context *torture)
223 {
224         bool correct = true;
225         int torture_nprocs = torture_setting_int(torture, "nprocs", 4);
226         struct smbcli_state *cli;
227         const char *p;
228
229         read_only = torture_setting_bool(torture, "readonly", false);
230
231         nb_max_retries = torture_setting_int(torture, "nretries", 1);
232
233         p = torture_setting_string(torture, "timelimit", NULL);
234         if (p && *p) {
235                 timelimit = atoi(p);
236         }
237
238         warmup = timelimit / 20;
239
240         loadfile = torture_setting_string(torture, "loadfile", NULL);
241         if (!loadfile || !*loadfile) {
242                 loadfile = "client.txt";
243         }
244
245         if (torture_nprocs > 1) {
246                 if (!torture_open_connection(&cli, torture, 0)) {
247                         return false;
248                 }
249
250                 if (!read_only && !torture_setup_dir(cli, "\\clients")) {
251                         return false;
252                 }
253         }
254
255         nbio_shmem(torture_nprocs, timelimit, warmup);
256
257         printf("Running for %d seconds with load '%s' and warmup %d secs\n", 
258                timelimit, loadfile, warmup);
259
260         /* we need to reset SIGCHLD here as the name resolution
261            library may have changed it. We rely on correct signals
262            from childs in the main torture code which reaps
263            children. This is why smbtorture BENCH-NBENCH was sometimes
264            failing */
265         signal(SIGCHLD, SIG_DFL);
266
267
268         signal(SIGALRM, nb_alarm);
269         alarm(1);
270         torture_create_procs(torture, run_netbench, &correct);
271         alarm(0);
272
273         if (!read_only && torture_nprocs > 1) {
274                 smbcli_deltree(cli->tree, "\\clients");
275         }
276
277         printf("\nThroughput %g MB/sec\n", nbio_result());
278         return correct;
279 }
280
281 NTSTATUS torture_nbench_init(void)
282 {
283         struct torture_suite *suite = 
284                 torture_suite_create(
285                         talloc_autofree_context(),
286                         "BENCH");
287
288         torture_suite_add_simple_test(suite, "NBENCH", torture_nbench);
289
290         suite->description = talloc_strdup(suite, "Benchmarks");
291
292         torture_register_suite(suite);
293         return NT_STATUS_OK;
294 }