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