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