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