2 Unix SMB/CIFS implementation.
3 SMB torture tester - NBENCH test
4 Copyright (C) Andrew Tridgell 1997-2004
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.
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.
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/>.
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"
28 #include "torture/nbench/proto.h"
30 int nbench_line_count = 0;
31 static int timelimit = 600;
33 static const char *loadfile;
36 #define ival(s) strtoll(s, NULL, 0)
38 static unsigned long nb_max_retries;
40 #define NB_RETRY(op) \
41 for (n=0;n<=nb_max_retries && !op;n++) do_reconnect(&cli, tctx, client)
43 static void do_reconnect(struct smbcli_state **cli, struct torture_context *tctx, int client)
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);
53 printf("[%d] Failed to reconnect client %d\n", nbench_line_count, client);
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)
60 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
66 double target_rate = torture_setting_double(tctx, "targetrate", 0);
69 if (target_rate != 0 && client == 0) {
70 printf("Targetting %.4f MByte/sec\n", target_rate);
73 nb_setup(cli, client);
75 if (torture_nprocs == 1) {
77 NB_RETRY(torture_setup_dir(cli, "\\clients"));
81 asprintf(&cname, "client%d", client+1);
83 f = fopen(loadfile, "r");
93 while (fgets(line, sizeof(line)-1, f)) {
95 const char **params0, **params;
99 line[strlen(line)-1] = 0;
101 all_string_sub(line,"client1", cname, sizeof(line));
103 params = params0 = str_list_make_shell(NULL, line, " ");
104 i = str_list_length(params);
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);
111 nbio_time_delay(targett);
115 } else if (target_rate != 0) {
116 nbio_target_rate(target_rate);
119 if (i < 2 || params[0][0] == '#') continue;
121 if (!strncmp(params[0],"SMB", 3)) {
122 printf("ERROR: You are using a dbench 1 load file\n");
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);
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));
137 status = nt_status_string_to_code(params[i-1]);
140 DEBUG(9,("run_netbench(%d): %s %s\n", client, params[0], params[1]));
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]),
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]),
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]),
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);
191 printf("[%d] Unknown operation %s\n", nbench_line_count, params[0]);
194 if (n > nb_max_retries) {
195 printf("Maximum reconnect retries reached for op '%s'\n", params[0]);
199 talloc_free(params0);
201 if (nb_tick()) goto done;
210 if (!read_only && torture_nprocs == 1) {
211 smbcli_deltree(cli->tree, "\\clients");
213 if (!torture_close_connection(cli)) {
221 /* run a test that simulates an approximate netbench client load */
222 bool torture_nbench(struct torture_context *torture)
225 int torture_nprocs = torture_setting_int(torture, "nprocs", 4);
226 struct smbcli_state *cli;
229 read_only = torture_setting_bool(torture, "readonly", false);
231 nb_max_retries = torture_setting_int(torture, "nretries", 1);
233 p = torture_setting_string(torture, "timelimit", NULL);
238 warmup = timelimit / 20;
240 loadfile = torture_setting_string(torture, "loadfile", NULL);
241 if (!loadfile || !*loadfile) {
242 loadfile = "client.txt";
245 if (torture_nprocs > 1) {
246 if (!torture_open_connection(&cli, torture, 0)) {
250 if (!read_only && !torture_setup_dir(cli, "\\clients")) {
255 nbio_shmem(torture_nprocs, timelimit, warmup);
257 printf("Running for %d seconds with load '%s' and warmup %d secs\n",
258 timelimit, loadfile, warmup);
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
265 signal(SIGCHLD, SIG_DFL);
268 signal(SIGALRM, nb_alarm);
270 torture_create_procs(torture, run_netbench, &correct);
273 if (!read_only && torture_nprocs > 1) {
274 smbcli_deltree(cli->tree, "\\clients");
277 printf("\nThroughput %g MB/sec\n", nbio_result());
281 NTSTATUS torture_nbench_init(void)
283 struct torture_suite *suite =
284 torture_suite_create(
285 talloc_autofree_context(),
288 torture_suite_add_simple_test(suite, "NBENCH", torture_nbench);
290 suite->description = talloc_strdup(suite, "Benchmarks");
292 torture_register_suite(suite);