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