ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / torture / smb2 / bench.c
blob2474028a7231ef4325a0501ef8bc218dcce53f69
1 /*
2 Unix SMB/CIFS implementation.
4 SMB2 bench test suite
6 Copyright (C) Stefan Metzmacher 2022
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "lib/param/param.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "libcli/smb/smbXcli_base.h"
27 #include "torture/torture.h"
28 #include "torture/util.h"
29 #include "torture/smb2/proto.h"
30 #include "librpc/gen_ndr/ndr_security.h"
31 #include "libcli/security/security.h"
33 #include "system/filesys.h"
34 #include "auth/credentials/credentials.h"
35 #include "lib/cmdline/cmdline.h"
36 #include "librpc/gen_ndr/security.h"
37 #include "lib/events/events.h"
39 #define FNAME "test_create.dat"
40 #define DNAME "smb2_open"
42 #define CHECK_STATUS(status, correct) do { \
43 if (!NT_STATUS_EQUAL(status, correct)) { \
44 torture_result(tctx, TORTURE_FAIL, \
45 "(%s) Incorrect status %s - should be %s\n", \
46 __location__, nt_errstr(status), nt_errstr(correct)); \
47 return false; \
48 }} while (0)
50 #define CHECK_EQUAL(v, correct) do { \
51 if (v != correct) { \
52 torture_result(tctx, TORTURE_FAIL, \
53 "(%s) Incorrect value for %s 0x%08llx - " \
54 "should be 0x%08llx\n", \
55 __location__, #v, \
56 (unsigned long long)v, \
57 (unsigned long long)correct); \
58 return false; \
59 }} while (0)
61 #define CHECK_TIME(t, field) do { \
62 time_t t1, t2; \
63 finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
64 finfo.all_info.in.file.handle = h1; \
65 status = smb2_getinfo_file(tree, tctx, &finfo); \
66 CHECK_STATUS(status, NT_STATUS_OK); \
67 t1 = t & ~1; \
68 t2 = nt_time_to_unix(finfo.all_info.out.field) & ~1; \
69 if (abs(t1-t2) > 2) { \
70 torture_result(tctx, TORTURE_FAIL, \
71 "(%s) wrong time for field %s %s - %s\n", \
72 __location__, #field, \
73 timestring(tctx, t1), \
74 timestring(tctx, t2)); \
75 dump_all_info(tctx, &finfo); \
76 ret = false; \
77 }} while (0)
79 #define CHECK_NTTIME(t, field) do { \
80 NTTIME t2; \
81 finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
82 finfo.all_info.in.file.handle = h1; \
83 status = smb2_getinfo_file(tree, tctx, &finfo); \
84 CHECK_STATUS(status, NT_STATUS_OK); \
85 t2 = finfo.all_info.out.field; \
86 if (llabs((int64_t)(t-t2)) > 20000) { \
87 torture_result(tctx, TORTURE_FAIL, \
88 "(%s) wrong time for field %s %s - %s\n", \
89 __location__, #field, \
90 nt_time_string(tctx, t), \
91 nt_time_string(tctx, t2)); \
92 dump_all_info(tctx, &finfo); \
93 ret = false; \
94 }} while (0)
96 #define CHECK_ALL_INFO(v, field) do { \
97 finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
98 finfo.all_info.in.file.handle = h1; \
99 status = smb2_getinfo_file(tree, tctx, &finfo); \
100 CHECK_STATUS(status, NT_STATUS_OK); \
101 if ((v) != (finfo.all_info.out.field)) { \
102 torture_result(tctx, TORTURE_FAIL, \
103 "(%s) wrong value for field %s 0x%x - 0x%x\n", \
104 __location__, #field, (int)v,\
105 (int)(finfo.all_info.out.field)); \
106 dump_all_info(tctx, &finfo); \
107 ret = false; \
108 }} while (0)
110 #define CHECK_VAL(v, correct) do { \
111 if ((v) != (correct)) { \
112 torture_result(tctx, TORTURE_FAIL, \
113 "(%s) wrong value for %s 0x%x - should be 0x%x\n", \
114 __location__, #v, (int)(v), (int)correct); \
115 ret = false; \
116 }} while (0)
118 #define SET_ATTRIB(sattrib) do { \
119 union smb_setfileinfo sfinfo; \
120 ZERO_STRUCT(sfinfo.basic_info.in); \
121 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION; \
122 sfinfo.basic_info.in.file.handle = h1; \
123 sfinfo.basic_info.in.attrib = sattrib; \
124 status = smb2_setinfo_file(tree, &sfinfo); \
125 if (!NT_STATUS_IS_OK(status)) { \
126 torture_comment(tctx, \
127 "(%s) Failed to set attrib 0x%x on %s\n", \
128 __location__, (unsigned int)(sattrib), fname); \
129 }} while (0)
132 stress testing keepalive iops
135 struct test_smb2_bench_echo_conn;
136 struct test_smb2_bench_echo_loop;
138 struct test_smb2_bench_echo_state {
139 struct torture_context *tctx;
140 size_t num_conns;
141 struct test_smb2_bench_echo_conn *conns;
142 size_t num_loops;
143 struct test_smb2_bench_echo_loop *loops;
144 size_t pending_loops;
145 struct timeval starttime;
146 int timecount;
147 int timelimit;
148 uint64_t num_finished;
149 double total_latency;
150 double min_latency;
151 double max_latency;
152 bool ok;
153 bool stop;
156 struct test_smb2_bench_echo_conn {
157 struct test_smb2_bench_echo_state *state;
158 int idx;
159 struct smb2_tree *tree;
162 struct test_smb2_bench_echo_loop {
163 struct test_smb2_bench_echo_state *state;
164 struct test_smb2_bench_echo_conn *conn;
165 int idx;
166 struct tevent_immediate *im;
167 struct tevent_req *req;
168 struct timeval starttime;
169 uint64_t num_started;
170 uint64_t num_finished;
171 uint64_t total_finished;
172 uint64_t max_finished;
173 double total_latency;
174 double min_latency;
175 double max_latency;
176 NTSTATUS error;
179 static void test_smb2_bench_echo_loop_do(
180 struct test_smb2_bench_echo_loop *loop);
182 static void test_smb2_bench_echo_loop_start(struct tevent_context *ctx,
183 struct tevent_immediate *im,
184 void *private_data)
186 struct test_smb2_bench_echo_loop *loop =
187 (struct test_smb2_bench_echo_loop *)
188 private_data;
190 test_smb2_bench_echo_loop_do(loop);
193 static void test_smb2_bench_echo_loop_done(struct tevent_req *req);
195 static void test_smb2_bench_echo_loop_do(
196 struct test_smb2_bench_echo_loop *loop)
198 struct test_smb2_bench_echo_state *state = loop->state;
200 loop->num_started += 1;
201 loop->starttime = timeval_current();
202 loop->req = smb2cli_echo_send(state->loops,
203 state->tctx->ev,
204 loop->conn->tree->session->transport->conn,
205 1000);
206 torture_assert_goto(state->tctx, loop->req != NULL,
207 state->ok, asserted, "smb2cli_echo_send");
209 tevent_req_set_callback(loop->req,
210 test_smb2_bench_echo_loop_done,
211 loop);
212 return;
213 asserted:
214 state->stop = true;
217 static void test_smb2_bench_echo_loop_done(struct tevent_req *req)
219 struct test_smb2_bench_echo_loop *loop =
220 (struct test_smb2_bench_echo_loop *)
221 _tevent_req_callback_data(req);
222 struct test_smb2_bench_echo_state *state = loop->state;
223 double latency = timeval_elapsed(&loop->starttime);
224 TALLOC_CTX *frame = talloc_stackframe();
226 torture_assert_goto(state->tctx, loop->req == req,
227 state->ok, asserted, __location__);
228 loop->error = smb2cli_echo_recv(req);
229 torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
230 state->ok, asserted, __location__);
231 SMB_ASSERT(latency >= 0.000001);
233 if (loop->num_finished == 0) {
234 /* first round */
235 loop->min_latency = latency;
236 loop->max_latency = latency;
239 loop->num_finished += 1;
240 loop->total_finished += 1;
241 loop->total_latency += latency;
243 if (latency < loop->min_latency) {
244 loop->min_latency = latency;
247 if (latency > loop->max_latency) {
248 loop->max_latency = latency;
251 if (loop->total_finished >= loop->max_finished) {
252 if (state->pending_loops > 0) {
253 state->pending_loops -= 1;
255 if (state->pending_loops == 0) {
256 goto asserted;
260 TALLOC_FREE(frame);
261 test_smb2_bench_echo_loop_do(loop);
262 return;
263 asserted:
264 state->stop = true;
265 TALLOC_FREE(frame);
268 static void test_smb2_bench_echo_progress(struct tevent_context *ev,
269 struct tevent_timer *te,
270 struct timeval current_time,
271 void *private_data)
273 struct test_smb2_bench_echo_state *state =
274 (struct test_smb2_bench_echo_state *)private_data;
275 uint64_t num_echos = 0;
276 double total_echo_latency = 0;
277 double min_echo_latency = 0;
278 double max_echo_latency = 0;
279 double avs_echo_latency = 0;
280 size_t i;
282 state->timecount += 1;
284 for (i=0;i<state->num_loops;i++) {
285 struct test_smb2_bench_echo_loop *loop =
286 &state->loops[i];
288 num_echos += loop->num_finished;
289 total_echo_latency += loop->total_latency;
290 if (min_echo_latency == 0.0 && loop->min_latency != 0.0) {
291 min_echo_latency = loop->min_latency;
293 if (loop->min_latency < min_echo_latency) {
294 min_echo_latency = loop->min_latency;
296 if (max_echo_latency == 0.0) {
297 max_echo_latency = loop->max_latency;
299 if (loop->max_latency > max_echo_latency) {
300 max_echo_latency = loop->max_latency;
302 loop->num_finished = 0;
303 loop->total_latency = 0.0;
306 state->num_finished += num_echos;
307 state->total_latency += total_echo_latency;
308 if (state->min_latency == 0.0 && min_echo_latency != 0.0) {
309 state->min_latency = min_echo_latency;
311 if (min_echo_latency < state->min_latency) {
312 state->min_latency = min_echo_latency;
314 if (state->max_latency == 0.0) {
315 state->max_latency = max_echo_latency;
317 if (max_echo_latency > state->max_latency) {
318 state->max_latency = max_echo_latency;
321 if (state->timecount < state->timelimit) {
322 te = tevent_add_timer(state->tctx->ev,
323 state,
324 timeval_current_ofs(1, 0),
325 test_smb2_bench_echo_progress,
326 state);
327 torture_assert_goto(state->tctx, te != NULL,
328 state->ok, asserted, "tevent_add_timer");
330 if (!torture_setting_bool(state->tctx, "progress", true)) {
331 return;
334 avs_echo_latency = total_echo_latency / num_echos;
336 torture_comment(state->tctx,
337 "%.2f second: "
338 "echo[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] \r",
339 timeval_elapsed(&state->starttime),
340 (unsigned long long)num_echos,
341 avs_echo_latency,
342 min_echo_latency,
343 max_echo_latency);
344 return;
347 avs_echo_latency = state->total_latency / state->num_finished;
348 num_echos = state->num_finished / state->timelimit;
350 torture_comment(state->tctx,
351 "%.2f second: "
352 "echo[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
353 timeval_elapsed(&state->starttime),
354 (unsigned long long)num_echos,
355 avs_echo_latency,
356 state->min_latency,
357 state->max_latency);
359 asserted:
360 state->stop = true;
363 static bool test_smb2_bench_echo(struct torture_context *tctx,
364 struct smb2_tree *tree)
366 struct test_smb2_bench_echo_state *state = NULL;
367 bool ret = true;
368 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
369 int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
370 size_t i;
371 size_t li = 0;
372 int looplimit = torture_setting_int(tctx, "looplimit", -1);
373 int timelimit = torture_setting_int(tctx, "timelimit", 10);
374 struct tevent_timer *te = NULL;
375 uint32_t timeout_msec;
377 state = talloc_zero(tctx, struct test_smb2_bench_echo_state);
378 torture_assert(tctx, state != NULL, __location__);
379 state->tctx = tctx;
380 state->num_conns = torture_nprocs;
381 state->conns = talloc_zero_array(state,
382 struct test_smb2_bench_echo_conn,
383 state->num_conns);
384 torture_assert(tctx, state->conns != NULL, __location__);
385 state->num_loops = torture_nprocs * torture_qdepth;
386 state->loops = talloc_zero_array(state,
387 struct test_smb2_bench_echo_loop,
388 state->num_loops);
389 torture_assert(tctx, state->loops != NULL, __location__);
390 state->ok = true;
391 state->timelimit = MAX(timelimit, 1);
393 timeout_msec = tree->session->transport->options.request_timeout * 1000;
395 torture_comment(tctx, "Opening %zu connections\n", state->num_conns);
397 for (i=0;i<state->num_conns;i++) {
398 struct smb2_tree *ct = NULL;
399 DATA_BLOB out_input_buffer = data_blob_null;
400 DATA_BLOB out_output_buffer = data_blob_null;
401 size_t pcli;
403 state->conns[i].state = state;
404 state->conns[i].idx = i;
406 if (!torture_smb2_connection(tctx, &ct)) {
407 torture_comment(tctx, "Failed opening %zu/%zu connections\n", i, state->num_conns);
408 return false;
410 state->conns[i].tree = talloc_steal(state->conns, ct);
412 smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
413 smb2cli_ioctl(ct->session->transport->conn,
414 timeout_msec,
415 ct->session->smbXcli,
416 ct->smbXcli,
417 UINT64_MAX, /* in_fid_persistent */
418 UINT64_MAX, /* in_fid_volatile */
419 UINT32_MAX,
420 0, /* in_max_input_length */
421 NULL, /* in_input_buffer */
422 1, /* in_max_output_length */
423 NULL, /* in_output_buffer */
424 SMB2_IOCTL_FLAG_IS_FSCTL,
426 &out_input_buffer,
427 &out_output_buffer);
428 torture_assert(tctx,
429 smbXcli_conn_is_connected(ct->session->transport->conn),
430 "smbXcli_conn_is_connected");
432 for (pcli = 0; pcli < torture_qdepth; pcli++) {
433 struct test_smb2_bench_echo_loop *loop = &state->loops[li];
435 loop->idx = li++;
436 if (looplimit != -1) {
437 loop->max_finished = looplimit;
438 } else {
439 loop->max_finished = UINT64_MAX;
441 loop->state = state;
442 loop->conn = &state->conns[i];
443 loop->im = tevent_create_immediate(state->loops);
444 torture_assert(tctx, loop->im != NULL, __location__);
446 tevent_schedule_immediate(loop->im,
447 tctx->ev,
448 test_smb2_bench_echo_loop_start,
449 loop);
453 torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
454 state->num_conns, torture_qdepth, state->num_loops);
456 torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
458 state->starttime = timeval_current();
459 state->pending_loops = state->num_loops;
461 te = tevent_add_timer(tctx->ev,
462 state,
463 timeval_current_ofs(1, 0),
464 test_smb2_bench_echo_progress,
465 state);
466 torture_assert(tctx, te != NULL, __location__);
468 while (!state->stop) {
469 int rc = tevent_loop_once(tctx->ev);
470 torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
473 torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
474 TALLOC_FREE(state);
475 return ret;
479 stress testing path base operations
480 e.g. contention on lockting.tdb records
483 struct test_smb2_bench_path_contention_shared_conn;
484 struct test_smb2_bench_path_contention_shared_loop;
486 struct test_smb2_bench_path_contention_shared_state {
487 struct torture_context *tctx;
488 size_t num_conns;
489 struct test_smb2_bench_path_contention_shared_conn *conns;
490 size_t num_loops;
491 struct test_smb2_bench_path_contention_shared_loop *loops;
492 struct timeval starttime;
493 int timecount;
494 int timelimit;
495 struct {
496 uint64_t num_finished;
497 double total_latency;
498 double min_latency;
499 double max_latency;
500 } opens;
501 struct {
502 uint64_t num_finished;
503 double total_latency;
504 double min_latency;
505 double max_latency;
506 } closes;
507 bool ok;
508 bool stop;
511 struct test_smb2_bench_path_contention_shared_conn {
512 struct test_smb2_bench_path_contention_shared_state *state;
513 int idx;
514 struct smb2_tree *tree;
517 struct test_smb2_bench_path_contention_shared_loop {
518 struct test_smb2_bench_path_contention_shared_state *state;
519 struct test_smb2_bench_path_contention_shared_conn *conn;
520 int idx;
521 struct tevent_immediate *im;
522 struct {
523 struct smb2_create io;
524 struct smb2_request *req;
525 struct timeval starttime;
526 uint64_t num_started;
527 uint64_t num_finished;
528 double total_latency;
529 double min_latency;
530 double max_latency;
531 } opens;
532 struct {
533 struct smb2_close io;
534 struct smb2_request *req;
535 struct timeval starttime;
536 uint64_t num_started;
537 uint64_t num_finished;
538 double total_latency;
539 double min_latency;
540 double max_latency;
541 } closes;
542 NTSTATUS error;
545 static void test_smb2_bench_path_contention_loop_open(
546 struct test_smb2_bench_path_contention_shared_loop *loop);
548 static void test_smb2_bench_path_contention_loop_start(struct tevent_context *ctx,
549 struct tevent_immediate *im,
550 void *private_data)
552 struct test_smb2_bench_path_contention_shared_loop *loop =
553 (struct test_smb2_bench_path_contention_shared_loop *)
554 private_data;
556 test_smb2_bench_path_contention_loop_open(loop);
559 static void test_smb2_bench_path_contention_loop_opened(struct smb2_request *req);
561 static void test_smb2_bench_path_contention_loop_open(
562 struct test_smb2_bench_path_contention_shared_loop *loop)
564 struct test_smb2_bench_path_contention_shared_state *state = loop->state;
566 loop->opens.num_started += 1;
567 loop->opens.starttime = timeval_current();
568 loop->opens.req = smb2_create_send(loop->conn->tree, &loop->opens.io);
569 torture_assert_goto(state->tctx, loop->opens.req != NULL,
570 state->ok, asserted, "smb2_create_send");
572 loop->opens.req->async.fn = test_smb2_bench_path_contention_loop_opened;
573 loop->opens.req->async.private_data = loop;
574 return;
575 asserted:
576 state->stop = true;
579 static void test_smb2_bench_path_contention_loop_close(
580 struct test_smb2_bench_path_contention_shared_loop *loop);
582 static void test_smb2_bench_path_contention_loop_opened(struct smb2_request *req)
584 struct test_smb2_bench_path_contention_shared_loop *loop =
585 (struct test_smb2_bench_path_contention_shared_loop *)
586 req->async.private_data;
587 struct test_smb2_bench_path_contention_shared_state *state = loop->state;
588 double latency = timeval_elapsed(&loop->opens.starttime);
589 TALLOC_CTX *frame = talloc_stackframe();
591 torture_assert_goto(state->tctx, loop->opens.req == req,
592 state->ok, asserted, __location__);
593 loop->error = smb2_create_recv(req, frame, &loop->opens.io);
594 torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
595 state->ok, asserted, __location__);
596 ZERO_STRUCT(loop->opens.io.out.blobs);
597 SMB_ASSERT(latency >= 0.000001);
599 if (loop->opens.num_finished == 0) {
600 /* first round */
601 loop->opens.min_latency = latency;
602 loop->opens.max_latency = latency;
605 loop->opens.num_finished += 1;
606 loop->opens.total_latency += latency;
608 if (latency < loop->opens.min_latency) {
609 loop->opens.min_latency = latency;
612 if (latency > loop->opens.max_latency) {
613 loop->opens.max_latency = latency;
616 TALLOC_FREE(frame);
617 test_smb2_bench_path_contention_loop_close(loop);
618 return;
619 asserted:
620 state->stop = true;
621 TALLOC_FREE(frame);
624 static void test_smb2_bench_path_contention_loop_closed(struct smb2_request *req);
626 static void test_smb2_bench_path_contention_loop_close(
627 struct test_smb2_bench_path_contention_shared_loop *loop)
629 struct test_smb2_bench_path_contention_shared_state *state = loop->state;
631 loop->closes.num_started += 1;
632 loop->closes.starttime = timeval_current();
633 loop->closes.io.in.file = loop->opens.io.out.file;
634 loop->closes.req = smb2_close_send(loop->conn->tree, &loop->closes.io);
635 torture_assert_goto(state->tctx, loop->closes.req != NULL,
636 state->ok, asserted, "smb2_close_send");
638 loop->closes.req->async.fn = test_smb2_bench_path_contention_loop_closed;
639 loop->closes.req->async.private_data = loop;
640 return;
641 asserted:
642 state->stop = true;
645 static void test_smb2_bench_path_contention_loop_closed(struct smb2_request *req)
647 struct test_smb2_bench_path_contention_shared_loop *loop =
648 (struct test_smb2_bench_path_contention_shared_loop *)
649 req->async.private_data;
650 struct test_smb2_bench_path_contention_shared_state *state = loop->state;
651 double latency = timeval_elapsed(&loop->closes.starttime);
653 torture_assert_goto(state->tctx, loop->closes.req == req,
654 state->ok, asserted, __location__);
655 loop->error = smb2_close_recv(req, &loop->closes.io);
656 torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
657 state->ok, asserted, __location__);
658 SMB_ASSERT(latency >= 0.000001);
659 if (loop->closes.num_finished == 0) {
660 /* first round */
661 loop->closes.min_latency = latency;
662 loop->closes.max_latency = latency;
664 loop->closes.num_finished += 1;
666 loop->closes.total_latency += latency;
668 if (latency < loop->closes.min_latency) {
669 loop->closes.min_latency = latency;
672 if (latency > loop->closes.max_latency) {
673 loop->closes.max_latency = latency;
676 test_smb2_bench_path_contention_loop_open(loop);
677 return;
678 asserted:
679 state->stop = true;
682 static void test_smb2_bench_path_contention_progress(struct tevent_context *ev,
683 struct tevent_timer *te,
684 struct timeval current_time,
685 void *private_data)
687 struct test_smb2_bench_path_contention_shared_state *state =
688 (struct test_smb2_bench_path_contention_shared_state *)private_data;
689 uint64_t num_opens = 0;
690 double total_open_latency = 0;
691 double min_open_latency = 0;
692 double max_open_latency = 0;
693 double avs_open_latency = 0;
694 uint64_t num_closes = 0;
695 double total_close_latency = 0;
696 double min_close_latency = 0;
697 double max_close_latency = 0;
698 double avs_close_latency = 0;
699 size_t i;
701 state->timecount += 1;
703 for (i=0;i<state->num_loops;i++) {
704 struct test_smb2_bench_path_contention_shared_loop *loop =
705 &state->loops[i];
707 num_opens += loop->opens.num_finished;
708 total_open_latency += loop->opens.total_latency;
709 if (min_open_latency == 0.0 && loop->opens.min_latency != 0.0) {
710 min_open_latency = loop->opens.min_latency;
712 if (loop->opens.min_latency < min_open_latency) {
713 min_open_latency = loop->opens.min_latency;
715 if (max_open_latency == 0.0) {
716 max_open_latency = loop->opens.max_latency;
718 if (loop->opens.max_latency > max_open_latency) {
719 max_open_latency = loop->opens.max_latency;
721 loop->opens.num_finished = 0;
722 loop->opens.total_latency = 0.0;
724 num_closes += loop->closes.num_finished;
725 total_close_latency += loop->closes.total_latency;
726 if (min_close_latency == 0.0 && loop->closes.min_latency != 0.0) {
727 min_close_latency = loop->closes.min_latency;
729 if (loop->closes.min_latency < min_close_latency) {
730 min_close_latency = loop->closes.min_latency;
732 if (max_close_latency == 0.0) {
733 max_close_latency = loop->closes.max_latency;
735 if (loop->closes.max_latency > max_close_latency) {
736 max_close_latency = loop->closes.max_latency;
738 loop->closes.num_finished = 0;
739 loop->closes.total_latency = 0.0;
742 state->opens.num_finished += num_opens;
743 state->opens.total_latency += total_open_latency;
744 if (state->opens.min_latency == 0.0 && min_open_latency != 0.0) {
745 state->opens.min_latency = min_open_latency;
747 if (min_open_latency < state->opens.min_latency) {
748 state->opens.min_latency = min_open_latency;
750 if (state->opens.max_latency == 0.0) {
751 state->opens.max_latency = max_open_latency;
753 if (max_open_latency > state->opens.max_latency) {
754 state->opens.max_latency = max_open_latency;
757 state->closes.num_finished += num_closes;
758 state->closes.total_latency += total_close_latency;
759 if (state->closes.min_latency == 0.0 && min_close_latency != 0.0) {
760 state->closes.min_latency = min_close_latency;
762 if (min_close_latency < state->closes.min_latency) {
763 state->closes.min_latency = min_close_latency;
765 if (state->closes.max_latency == 0.0) {
766 state->closes.max_latency = max_close_latency;
768 if (max_close_latency > state->closes.max_latency) {
769 state->closes.max_latency = max_close_latency;
772 if (state->timecount < state->timelimit) {
773 te = tevent_add_timer(state->tctx->ev,
774 state,
775 timeval_current_ofs(1, 0),
776 test_smb2_bench_path_contention_progress,
777 state);
778 torture_assert_goto(state->tctx, te != NULL,
779 state->ok, asserted, "tevent_add_timer");
781 if (!torture_setting_bool(state->tctx, "progress", true)) {
782 return;
785 avs_open_latency = total_open_latency / num_opens;
786 avs_close_latency = total_close_latency / num_closes;
788 torture_comment(state->tctx,
789 "%.2f second: "
790 "open[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
791 "close[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] \r",
792 timeval_elapsed(&state->starttime),
793 (unsigned long long)num_opens,
794 avs_open_latency,
795 min_open_latency,
796 max_open_latency,
797 (unsigned long long)num_closes,
798 avs_close_latency,
799 min_close_latency,
800 max_close_latency);
801 return;
804 avs_open_latency = state->opens.total_latency / state->opens.num_finished;
805 avs_close_latency = state->closes.total_latency / state->closes.num_finished;
806 num_opens = state->opens.num_finished / state->timelimit;
807 num_closes = state->closes.num_finished / state->timelimit;
809 torture_comment(state->tctx,
810 "%.2f second: "
811 "open[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
812 "close[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
813 timeval_elapsed(&state->starttime),
814 (unsigned long long)num_opens,
815 avs_open_latency,
816 state->opens.min_latency,
817 state->opens.max_latency,
818 (unsigned long long)num_closes,
819 avs_close_latency,
820 state->closes.min_latency,
821 state->closes.max_latency);
823 asserted:
824 state->stop = true;
827 bool test_smb2_bench_path_contention_shared(struct torture_context *tctx,
828 struct smb2_tree *tree)
830 struct test_smb2_bench_path_contention_shared_state *state = NULL;
831 bool ret = true;
832 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
833 int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
834 size_t i;
835 size_t li = 0;
836 int timelimit = torture_setting_int(tctx, "timelimit", 10);
837 const char *path = torture_setting_string(tctx, "bench_path", "");
838 struct smb2_create open_io = { .level = RAW_OPEN_SMB2, };
839 struct smb2_close close_io = { .level = RAW_CLOSE_SMB2, };
840 struct tevent_timer *te = NULL;
841 uint32_t timeout_msec;
843 state = talloc_zero(tctx, struct test_smb2_bench_path_contention_shared_state);
844 torture_assert(tctx, state != NULL, __location__);
845 state->tctx = tctx;
846 state->num_conns = torture_nprocs;
847 state->conns = talloc_zero_array(state,
848 struct test_smb2_bench_path_contention_shared_conn,
849 state->num_conns);
850 torture_assert(tctx, state->conns != NULL, __location__);
851 state->num_loops = torture_nprocs * torture_qdepth;
852 state->loops = talloc_zero_array(state,
853 struct test_smb2_bench_path_contention_shared_loop,
854 state->num_loops);
855 torture_assert(tctx, state->loops != NULL, __location__);
856 state->ok = true;
857 state->timelimit = MAX(timelimit, 1);
859 open_io.in.desired_access = SEC_DIR_READ_ATTRIBUTE;
860 open_io.in.alloc_size = 0;
861 open_io.in.file_attributes = 0;
862 open_io.in.share_access = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
863 open_io.in.create_disposition = FILE_OPEN;
864 open_io.in.create_options = FILE_OPEN_REPARSE_POINT;
865 open_io.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
866 open_io.in.security_flags = 0;
867 open_io.in.fname = path;
868 open_io.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
869 open_io.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
871 timeout_msec = tree->session->transport->options.request_timeout * 1000;
873 torture_comment(tctx, "Opening %zd connections\n", state->num_conns);
875 for (i=0;i<state->num_conns;i++) {
876 struct smb2_tree *ct = NULL;
877 DATA_BLOB out_input_buffer = data_blob_null;
878 DATA_BLOB out_output_buffer = data_blob_null;
879 size_t pcli;
881 state->conns[i].state = state;
882 state->conns[i].idx = i;
884 if (!torture_smb2_connection(tctx, &ct)) {
885 torture_comment(tctx, "Failed opening %zd/%zd connections\n", i, state->num_conns);
886 return false;
888 state->conns[i].tree = talloc_steal(state->conns, ct);
890 smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
891 smb2cli_ioctl(ct->session->transport->conn,
892 timeout_msec,
893 ct->session->smbXcli,
894 ct->smbXcli,
895 UINT64_MAX, /* in_fid_persistent */
896 UINT64_MAX, /* in_fid_volatile */
897 UINT32_MAX,
898 0, /* in_max_input_length */
899 NULL, /* in_input_buffer */
900 1, /* in_max_output_length */
901 NULL, /* in_output_buffer */
902 SMB2_IOCTL_FLAG_IS_FSCTL,
904 &out_input_buffer,
905 &out_output_buffer);
906 torture_assert(tctx,
907 smbXcli_conn_is_connected(ct->session->transport->conn),
908 "smbXcli_conn_is_connected");
909 for (pcli = 0; pcli < torture_qdepth; pcli++) {
910 struct test_smb2_bench_path_contention_shared_loop *loop = &state->loops[li];
912 loop->idx = li++;
913 loop->state = state;
914 loop->conn = &state->conns[i];
915 loop->im = tevent_create_immediate(state->loops);
916 torture_assert(tctx, loop->im != NULL, __location__);
917 loop->opens.io = open_io;
918 loop->closes.io = close_io;
920 tevent_schedule_immediate(loop->im,
921 tctx->ev,
922 test_smb2_bench_path_contention_loop_start,
923 loop);
927 torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
928 state->num_conns, torture_qdepth, state->num_loops);
930 torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
932 state->starttime = timeval_current();
934 te = tevent_add_timer(tctx->ev,
935 state,
936 timeval_current_ofs(1, 0),
937 test_smb2_bench_path_contention_progress,
938 state);
939 torture_assert(tctx, te != NULL, __location__);
941 while (!state->stop) {
942 int rc = tevent_loop_once(tctx->ev);
943 torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
946 torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
947 TALLOC_FREE(state);
948 return ret;
952 stress testing read iops
955 struct test_smb2_bench_read_conn;
956 struct test_smb2_bench_read_loop;
958 struct test_smb2_bench_read_state {
959 struct torture_context *tctx;
960 size_t num_conns;
961 struct test_smb2_bench_read_conn *conns;
962 size_t num_loops;
963 struct test_smb2_bench_read_loop *loops;
964 size_t pending_loops;
965 uint32_t io_size;
966 struct timeval starttime;
967 int timecount;
968 int timelimit;
969 uint64_t num_finished;
970 double total_latency;
971 double min_latency;
972 double max_latency;
973 bool ok;
974 bool stop;
977 struct test_smb2_bench_read_conn {
978 struct test_smb2_bench_read_state *state;
979 int idx;
980 struct smb2_tree *tree;
983 struct test_smb2_bench_read_loop {
984 struct test_smb2_bench_read_state *state;
985 struct test_smb2_bench_read_conn *conn;
986 int idx;
987 struct tevent_immediate *im;
988 char *fname;
989 struct smb2_handle handle;
990 struct tevent_req *req;
991 struct timeval starttime;
992 uint64_t num_started;
993 uint64_t num_finished;
994 uint64_t total_finished;
995 uint64_t max_finished;
996 double total_latency;
997 double min_latency;
998 double max_latency;
999 NTSTATUS error;
1002 static void test_smb2_bench_read_loop_do(
1003 struct test_smb2_bench_read_loop *loop);
1005 static void test_smb2_bench_read_loop_start(struct tevent_context *ctx,
1006 struct tevent_immediate *im,
1007 void *private_data)
1009 struct test_smb2_bench_read_loop *loop =
1010 (struct test_smb2_bench_read_loop *)
1011 private_data;
1013 test_smb2_bench_read_loop_do(loop);
1016 static void test_smb2_bench_read_loop_done(struct tevent_req *req);
1018 static void test_smb2_bench_read_loop_do(
1019 struct test_smb2_bench_read_loop *loop)
1021 struct test_smb2_bench_read_state *state = loop->state;
1022 uint32_t timeout_msec;
1024 timeout_msec = loop->conn->tree->session->transport->options.request_timeout * 1000;
1026 loop->num_started += 1;
1027 loop->starttime = timeval_current();
1028 loop->req = smb2cli_read_send(state->loops,
1029 state->tctx->ev,
1030 loop->conn->tree->session->transport->conn,
1031 timeout_msec,
1032 loop->conn->tree->session->smbXcli,
1033 loop->conn->tree->smbXcli,
1034 state->io_size, /* length */
1035 0, /* offset */
1036 loop->handle.data[0],/* fid_persistent */
1037 loop->handle.data[1],/* fid_volatile */
1038 state->io_size, /* minimum_count */
1039 0); /* remaining_bytes */
1040 torture_assert_goto(state->tctx, loop->req != NULL,
1041 state->ok, asserted, "smb2cli_read_send");
1043 tevent_req_set_callback(loop->req,
1044 test_smb2_bench_read_loop_done,
1045 loop);
1046 return;
1047 asserted:
1048 state->stop = true;
1051 static void test_smb2_bench_read_loop_done(struct tevent_req *req)
1053 struct test_smb2_bench_read_loop *loop =
1054 (struct test_smb2_bench_read_loop *)
1055 _tevent_req_callback_data(req);
1056 struct test_smb2_bench_read_state *state = loop->state;
1057 double latency = timeval_elapsed(&loop->starttime);
1058 TALLOC_CTX *frame = talloc_stackframe();
1059 uint8_t *data = NULL;
1060 uint32_t data_length = 0;
1062 torture_assert_goto(state->tctx, loop->req == req,
1063 state->ok, asserted, __location__);
1064 loop->error = smb2cli_read_recv(req, frame, &data, &data_length);
1065 torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
1066 state->ok, asserted, __location__);
1067 torture_assert_u32_equal_goto(state->tctx, data_length, state->io_size,
1068 state->ok, asserted, __location__);
1069 SMB_ASSERT(latency >= 0.000001);
1071 if (loop->num_finished == 0) {
1072 /* first round */
1073 loop->min_latency = latency;
1074 loop->max_latency = latency;
1077 loop->num_finished += 1;
1078 loop->total_finished += 1;
1079 loop->total_latency += latency;
1081 if (latency < loop->min_latency) {
1082 loop->min_latency = latency;
1085 if (latency > loop->max_latency) {
1086 loop->max_latency = latency;
1089 if (loop->total_finished >= loop->max_finished) {
1090 if (state->pending_loops > 0) {
1091 state->pending_loops -= 1;
1093 if (state->pending_loops == 0) {
1094 goto asserted;
1098 TALLOC_FREE(frame);
1099 test_smb2_bench_read_loop_do(loop);
1100 return;
1101 asserted:
1102 state->stop = true;
1103 TALLOC_FREE(frame);
1106 static void test_smb2_bench_read_progress(struct tevent_context *ev,
1107 struct tevent_timer *te,
1108 struct timeval current_time,
1109 void *private_data)
1111 struct test_smb2_bench_read_state *state =
1112 (struct test_smb2_bench_read_state *)private_data;
1113 uint64_t num_reads = 0;
1114 double total_read_latency = 0;
1115 double min_read_latency = 0;
1116 double max_read_latency = 0;
1117 double avs_read_latency = 0;
1118 size_t i;
1120 state->timecount += 1;
1122 for (i=0;i<state->num_loops;i++) {
1123 struct test_smb2_bench_read_loop *loop =
1124 &state->loops[i];
1126 num_reads += loop->num_finished;
1127 total_read_latency += loop->total_latency;
1128 if (min_read_latency == 0.0 && loop->min_latency != 0.0) {
1129 min_read_latency = loop->min_latency;
1131 if (loop->min_latency < min_read_latency) {
1132 min_read_latency = loop->min_latency;
1134 if (max_read_latency == 0.0) {
1135 max_read_latency = loop->max_latency;
1137 if (loop->max_latency > max_read_latency) {
1138 max_read_latency = loop->max_latency;
1140 loop->num_finished = 0;
1141 loop->total_latency = 0.0;
1144 state->num_finished += num_reads;
1145 state->total_latency += total_read_latency;
1146 if (state->min_latency == 0.0 && min_read_latency != 0.0) {
1147 state->min_latency = min_read_latency;
1149 if (min_read_latency < state->min_latency) {
1150 state->min_latency = min_read_latency;
1152 if (state->max_latency == 0.0) {
1153 state->max_latency = max_read_latency;
1155 if (max_read_latency > state->max_latency) {
1156 state->max_latency = max_read_latency;
1159 if (state->timecount < state->timelimit) {
1160 te = tevent_add_timer(state->tctx->ev,
1161 state,
1162 timeval_current_ofs(1, 0),
1163 test_smb2_bench_read_progress,
1164 state);
1165 torture_assert_goto(state->tctx, te != NULL,
1166 state->ok, asserted, "tevent_add_timer");
1168 if (!torture_setting_bool(state->tctx, "progress", true)) {
1169 return;
1172 avs_read_latency = total_read_latency / num_reads;
1174 torture_comment(state->tctx,
1175 "%.2f second: "
1176 "read[num/s=%llu,bytes/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] \r",
1177 timeval_elapsed(&state->starttime),
1178 (unsigned long long)num_reads,
1179 (unsigned long long)num_reads*state->io_size,
1180 avs_read_latency,
1181 min_read_latency,
1182 max_read_latency);
1183 return;
1186 avs_read_latency = state->total_latency / state->num_finished;
1187 num_reads = state->num_finished / state->timelimit;
1189 torture_comment(state->tctx,
1190 "%.2f second: "
1191 "read[num/s=%llu,bytes/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
1192 timeval_elapsed(&state->starttime),
1193 (unsigned long long)num_reads,
1194 (unsigned long long)num_reads*state->io_size,
1195 avs_read_latency,
1196 state->min_latency,
1197 state->max_latency);
1199 asserted:
1200 state->stop = true;
1203 static bool test_smb2_bench_read(struct torture_context *tctx,
1204 struct smb2_tree *tree)
1206 struct test_smb2_bench_read_state *state = NULL;
1207 bool ret = true;
1208 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
1209 int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
1210 int torture_io_size = torture_setting_int(tctx, "io_size", 4096);
1211 size_t i;
1212 size_t li = 0;
1213 int looplimit = torture_setting_int(tctx, "looplimit", -1);
1214 int timelimit = torture_setting_int(tctx, "timelimit", 10);
1215 struct tevent_timer *te = NULL;
1216 uint32_t timeout_msec;
1217 const char *dname = "bench_read_dir";
1218 const char *unique = generate_random_str(tctx, 8);
1219 struct smb2_handle dh;
1220 NTSTATUS status;
1222 smb2_deltree(tree, dname);
1224 status = torture_smb2_testdir(tree, dname, &dh);
1225 CHECK_STATUS(status, NT_STATUS_OK);
1226 status = smb2_util_close(tree, dh);
1227 CHECK_STATUS(status, NT_STATUS_OK);
1229 state = talloc_zero(tctx, struct test_smb2_bench_read_state);
1230 torture_assert(tctx, state != NULL, __location__);
1231 state->tctx = tctx;
1232 state->num_conns = torture_nprocs;
1233 state->conns = talloc_zero_array(state,
1234 struct test_smb2_bench_read_conn,
1235 state->num_conns);
1236 torture_assert(tctx, state->conns != NULL, __location__);
1237 state->num_loops = torture_nprocs * torture_qdepth;
1238 state->loops = talloc_zero_array(state,
1239 struct test_smb2_bench_read_loop,
1240 state->num_loops);
1241 torture_assert(tctx, state->loops != NULL, __location__);
1242 state->ok = true;
1243 state->timelimit = MAX(timelimit, 1);
1244 state->io_size = MAX(torture_io_size, 1);
1245 state->io_size = MIN(state->io_size, 16*1024*1024);
1247 timeout_msec = tree->session->transport->options.request_timeout * 1000;
1249 torture_comment(tctx, "Opening %zu connections\n", state->num_conns);
1251 for (i=0;i<state->num_conns;i++) {
1252 struct smb2_tree *ct = NULL;
1253 DATA_BLOB out_input_buffer = data_blob_null;
1254 DATA_BLOB out_output_buffer = data_blob_null;
1255 size_t pcli;
1257 state->conns[i].state = state;
1258 state->conns[i].idx = i;
1260 if (!torture_smb2_connection(tctx, &ct)) {
1261 torture_comment(tctx, "Failed opening %zu/%zu connections\n", i, state->num_conns);
1262 return false;
1264 state->conns[i].tree = talloc_steal(state->conns, ct);
1266 smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
1267 smb2cli_ioctl(ct->session->transport->conn,
1268 timeout_msec,
1269 ct->session->smbXcli,
1270 ct->smbXcli,
1271 UINT64_MAX, /* in_fid_persistent */
1272 UINT64_MAX, /* in_fid_volatile */
1273 UINT32_MAX,
1274 0, /* in_max_input_length */
1275 NULL, /* in_input_buffer */
1276 1, /* in_max_output_length */
1277 NULL, /* in_output_buffer */
1278 SMB2_IOCTL_FLAG_IS_FSCTL,
1280 &out_input_buffer,
1281 &out_output_buffer);
1282 torture_assert(tctx,
1283 smbXcli_conn_is_connected(ct->session->transport->conn),
1284 "smbXcli_conn_is_connected");
1286 for (pcli = 0; pcli < torture_qdepth; pcli++) {
1287 struct test_smb2_bench_read_loop *loop = &state->loops[li];
1288 struct smb2_create cr;
1289 union smb_setfileinfo sfinfo;
1291 loop->idx = li++;
1292 if (looplimit != -1) {
1293 loop->max_finished = looplimit;
1294 } else {
1295 loop->max_finished = UINT64_MAX;
1297 loop->state = state;
1298 loop->conn = &state->conns[i];
1299 loop->im = tevent_create_immediate(state->loops);
1300 torture_assert(tctx, loop->im != NULL, __location__);
1302 loop->fname = talloc_asprintf(state->loops,
1303 "%s\\%s_loop_%zu_conn_%zu_loop_%zu.dat",
1304 dname, unique, li, i, pcli);
1305 torture_assert(tctx, loop->fname != NULL, __location__);
1307 /* reasonable default parameters */
1308 ZERO_STRUCT(cr);
1309 cr.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1310 cr.in.alloc_size = state->io_size;
1311 cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
1312 cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1313 cr.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1314 cr.in.create_disposition = NTCREATEX_DISP_CREATE;
1315 cr.in.create_options =
1316 NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
1317 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1318 cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1319 cr.in.security_flags = 0;
1320 cr.in.fname = loop->fname;
1321 status = smb2_create(state->conns[i].tree, tctx, &cr);
1322 CHECK_STATUS(status, NT_STATUS_OK);
1323 loop->handle = cr.out.file.handle;
1325 ZERO_STRUCT(sfinfo);
1326 sfinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1327 sfinfo.end_of_file_info.in.file.handle = loop->handle;
1328 sfinfo.end_of_file_info.in.size = state->io_size;
1329 status = smb2_setinfo_file(state->conns[i].tree, &sfinfo);
1330 CHECK_STATUS(status, NT_STATUS_OK);
1332 tevent_schedule_immediate(loop->im,
1333 tctx->ev,
1334 test_smb2_bench_read_loop_start,
1335 loop);
1339 torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
1340 state->num_conns, torture_qdepth, state->num_loops);
1342 torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
1344 state->starttime = timeval_current();
1345 state->pending_loops = state->num_loops;
1347 te = tevent_add_timer(tctx->ev,
1348 state,
1349 timeval_current_ofs(1, 0),
1350 test_smb2_bench_read_progress,
1351 state);
1352 torture_assert(tctx, te != NULL, __location__);
1354 while (!state->stop) {
1355 int rc = tevent_loop_once(tctx->ev);
1356 torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
1359 torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
1360 TALLOC_FREE(state);
1361 smb2_deltree(tree, dname);
1362 return ret;
1366 stress testing session setups
1369 struct test_smb2_bench_session_setup_shared_conn;
1370 struct test_smb2_bench_session_setup_shared_loop;
1372 struct test_smb2_bench_session_setup_shared_state {
1373 struct torture_context *tctx;
1374 struct cli_credentials *credentials;
1375 struct gensec_settings *gensec_settings;
1376 size_t num_conns;
1377 struct test_smb2_bench_session_setup_shared_conn *conns;
1378 size_t num_loops;
1379 struct test_smb2_bench_session_setup_shared_loop *loops;
1380 struct timeval starttime;
1381 int timecount;
1382 int timelimit;
1383 struct {
1384 uint64_t num_finished;
1385 double total_latency;
1386 double min_latency;
1387 double max_latency;
1388 } setups;
1389 struct {
1390 uint64_t num_finished;
1391 double total_latency;
1392 double min_latency;
1393 double max_latency;
1394 } logoffs;
1395 bool ok;
1396 bool stop;
1399 struct test_smb2_bench_session_setup_shared_conn {
1400 struct test_smb2_bench_session_setup_shared_state *state;
1401 int idx;
1402 struct smb2_transport *transport;
1405 struct test_smb2_bench_session_setup_shared_loop {
1406 struct test_smb2_bench_session_setup_shared_state *state;
1407 struct test_smb2_bench_session_setup_shared_conn *conn;
1408 int idx;
1409 struct smb2_session *session;
1410 struct tevent_immediate *im;
1411 struct {
1412 struct tevent_req *req;
1413 struct timeval starttime;
1414 uint64_t num_started;
1415 uint64_t num_finished;
1416 double total_latency;
1417 double min_latency;
1418 double max_latency;
1419 } setups;
1420 struct {
1421 struct smb2_request *req;
1422 struct timeval starttime;
1423 uint64_t num_started;
1424 uint64_t num_finished;
1425 double total_latency;
1426 double min_latency;
1427 double max_latency;
1428 } logoffs;
1429 NTSTATUS error;
1432 static void test_smb2_bench_session_setup_loop_do_setup(
1433 struct test_smb2_bench_session_setup_shared_loop *loop);
1435 static void test_smb2_bench_session_setup_loop_start(struct tevent_context *ctx,
1436 struct tevent_immediate *im,
1437 void *private_data)
1439 struct test_smb2_bench_session_setup_shared_loop *loop =
1440 (struct test_smb2_bench_session_setup_shared_loop *)
1441 private_data;
1443 test_smb2_bench_session_setup_loop_do_setup(loop);
1446 static void test_smb2_bench_session_setup_loop_done_setup(struct tevent_req *subreq);
1448 static void test_smb2_bench_session_setup_loop_do_setup(
1449 struct test_smb2_bench_session_setup_shared_loop *loop)
1451 struct test_smb2_bench_session_setup_shared_state *state = loop->state;
1453 loop->session = smb2_session_init(loop->conn->transport,
1454 state->gensec_settings,
1455 loop->conn->transport);
1456 torture_assert_goto(state->tctx, loop->session != NULL,
1457 state->ok, asserted, "smb2_session_init");
1458 talloc_steal(state->conns, loop->conn->transport);
1460 loop->setups.num_started += 1;
1461 loop->setups.starttime = timeval_current();
1462 loop->setups.req = smb2_session_setup_spnego_send(loop->session,
1463 state->tctx->ev,
1464 loop->session,
1465 state->credentials,
1466 0); /* previous_session_id */
1467 torture_assert_goto(state->tctx, loop->setups.req != NULL,
1468 state->ok, asserted,
1469 "smb2_session_setup_spnego_send");
1471 tevent_req_set_callback(loop->setups.req,
1472 test_smb2_bench_session_setup_loop_done_setup,
1473 loop);
1474 return;
1475 asserted:
1476 state->stop = true;
1479 static void test_smb2_bench_session_setup_loop_do_logoff(
1480 struct test_smb2_bench_session_setup_shared_loop *loop);
1482 static void test_smb2_bench_session_setup_loop_done_setup(struct tevent_req *subreq)
1484 struct test_smb2_bench_session_setup_shared_loop *loop =
1485 (struct test_smb2_bench_session_setup_shared_loop *)
1486 tevent_req_callback_data_void(subreq);
1487 struct test_smb2_bench_session_setup_shared_state *state = loop->state;
1488 double latency = timeval_elapsed(&loop->setups.starttime);
1489 TALLOC_CTX *frame = talloc_stackframe();
1491 torture_assert_goto(state->tctx, loop->setups.req == subreq,
1492 state->ok, asserted, __location__);
1493 loop->setups.req = NULL;
1494 loop->error = smb2_session_setup_spnego_recv(subreq);
1495 TALLOC_FREE(subreq);
1496 torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
1497 state->ok, asserted, __location__);
1498 SMB_ASSERT(latency >= 0.000001);
1500 if (loop->setups.num_finished == 0) {
1501 /* first round */
1502 loop->setups.min_latency = latency;
1503 loop->setups.max_latency = latency;
1506 loop->setups.num_finished += 1;
1507 loop->setups.total_latency += latency;
1509 if (latency < loop->setups.min_latency) {
1510 loop->setups.min_latency = latency;
1513 if (latency > loop->setups.max_latency) {
1514 loop->setups.max_latency = latency;
1517 TALLOC_FREE(frame);
1518 test_smb2_bench_session_setup_loop_do_logoff(loop);
1519 return;
1520 asserted:
1521 state->stop = true;
1522 TALLOC_FREE(frame);
1525 static void test_smb2_bench_session_setup_loop_done_logoff(struct smb2_request *req);
1527 static void test_smb2_bench_session_setup_loop_do_logoff(
1528 struct test_smb2_bench_session_setup_shared_loop *loop)
1530 struct test_smb2_bench_session_setup_shared_state *state = loop->state;
1532 loop->logoffs.num_started += 1;
1533 loop->logoffs.starttime = timeval_current();
1534 loop->logoffs.req = smb2_logoff_send(loop->session);
1535 torture_assert_goto(state->tctx, loop->logoffs.req != NULL,
1536 state->ok, asserted, "smb2_logoff_send");
1538 loop->logoffs.req->async.fn = test_smb2_bench_session_setup_loop_done_logoff;
1539 loop->logoffs.req->async.private_data = loop;
1540 return;
1541 asserted:
1542 state->stop = true;
1545 static void test_smb2_bench_session_setup_loop_done_logoff(struct smb2_request *req)
1547 struct test_smb2_bench_session_setup_shared_loop *loop =
1548 (struct test_smb2_bench_session_setup_shared_loop *)
1549 req->async.private_data;
1550 struct test_smb2_bench_session_setup_shared_state *state = loop->state;
1551 double latency = timeval_elapsed(&loop->logoffs.starttime);
1553 torture_assert_goto(state->tctx, loop->logoffs.req == req,
1554 state->ok, asserted, __location__);
1555 loop->error = smb2_logoff_recv(req);
1556 torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
1557 state->ok, asserted, __location__);
1558 TALLOC_FREE(loop->session);
1559 SMB_ASSERT(latency >= 0.000001);
1560 if (loop->logoffs.num_finished == 0) {
1561 /* first round */
1562 loop->logoffs.min_latency = latency;
1563 loop->logoffs.max_latency = latency;
1565 loop->logoffs.num_finished += 1;
1567 loop->logoffs.total_latency += latency;
1569 if (latency < loop->logoffs.min_latency) {
1570 loop->logoffs.min_latency = latency;
1573 if (latency > loop->logoffs.max_latency) {
1574 loop->logoffs.max_latency = latency;
1577 test_smb2_bench_session_setup_loop_do_setup(loop);
1578 return;
1579 asserted:
1580 state->stop = true;
1583 static void test_smb2_bench_session_setup_progress(struct tevent_context *ev,
1584 struct tevent_timer *te,
1585 struct timeval current_time,
1586 void *private_data)
1588 struct test_smb2_bench_session_setup_shared_state *state =
1589 (struct test_smb2_bench_session_setup_shared_state *)private_data;
1590 uint64_t num_setups = 0;
1591 double total_setup_latency = 0;
1592 double min_setup_latency = 0;
1593 double max_setup_latency = 0;
1594 double avs_setup_latency = 0;
1595 uint64_t num_logoffs = 0;
1596 double total_logoff_latency = 0;
1597 double min_logoff_latency = 0;
1598 double max_logoff_latency = 0;
1599 double avs_logoff_latency = 0;
1600 size_t i;
1602 state->timecount += 1;
1604 for (i=0;i<state->num_loops;i++) {
1605 struct test_smb2_bench_session_setup_shared_loop *loop =
1606 &state->loops[i];
1608 num_setups += loop->setups.num_finished;
1609 total_setup_latency += loop->setups.total_latency;
1610 if (min_setup_latency == 0.0 && loop->setups.min_latency != 0.0) {
1611 min_setup_latency = loop->setups.min_latency;
1613 if (loop->setups.min_latency < min_setup_latency) {
1614 min_setup_latency = loop->setups.min_latency;
1616 if (max_setup_latency == 0.0) {
1617 max_setup_latency = loop->setups.max_latency;
1619 if (loop->setups.max_latency > max_setup_latency) {
1620 max_setup_latency = loop->setups.max_latency;
1622 loop->setups.num_finished = 0;
1623 loop->setups.total_latency = 0.0;
1625 num_logoffs += loop->logoffs.num_finished;
1626 total_logoff_latency += loop->logoffs.total_latency;
1627 if (min_logoff_latency == 0.0 && loop->logoffs.min_latency != 0.0) {
1628 min_logoff_latency = loop->logoffs.min_latency;
1630 if (loop->logoffs.min_latency < min_logoff_latency) {
1631 min_logoff_latency = loop->logoffs.min_latency;
1633 if (max_logoff_latency == 0.0) {
1634 max_logoff_latency = loop->logoffs.max_latency;
1636 if (loop->logoffs.max_latency > max_logoff_latency) {
1637 max_logoff_latency = loop->logoffs.max_latency;
1639 loop->logoffs.num_finished = 0;
1640 loop->logoffs.total_latency = 0.0;
1643 state->setups.num_finished += num_setups;
1644 state->setups.total_latency += total_setup_latency;
1645 if (state->setups.min_latency == 0.0 && min_setup_latency != 0.0) {
1646 state->setups.min_latency = min_setup_latency;
1648 if (min_setup_latency < state->setups.min_latency) {
1649 state->setups.min_latency = min_setup_latency;
1651 if (state->setups.max_latency == 0.0) {
1652 state->setups.max_latency = max_setup_latency;
1654 if (max_setup_latency > state->setups.max_latency) {
1655 state->setups.max_latency = max_setup_latency;
1658 state->logoffs.num_finished += num_logoffs;
1659 state->logoffs.total_latency += total_logoff_latency;
1660 if (state->logoffs.min_latency == 0.0 && min_logoff_latency != 0.0) {
1661 state->logoffs.min_latency = min_logoff_latency;
1663 if (min_logoff_latency < state->logoffs.min_latency) {
1664 state->logoffs.min_latency = min_logoff_latency;
1666 if (state->logoffs.max_latency == 0.0) {
1667 state->logoffs.max_latency = max_logoff_latency;
1669 if (max_logoff_latency > state->logoffs.max_latency) {
1670 state->logoffs.max_latency = max_logoff_latency;
1673 if (state->timecount < state->timelimit) {
1674 te = tevent_add_timer(state->tctx->ev,
1675 state,
1676 timeval_current_ofs(1, 0),
1677 test_smb2_bench_session_setup_progress,
1678 state);
1679 torture_assert_goto(state->tctx, te != NULL,
1680 state->ok, asserted, "tevent_add_timer");
1682 if (!torture_setting_bool(state->tctx, "progress", true)) {
1683 return;
1686 avs_setup_latency = total_setup_latency / num_setups;
1687 avs_logoff_latency = total_logoff_latency / num_logoffs;
1689 torture_comment(state->tctx,
1690 "%.2f second: "
1691 "setup[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
1692 "logoff[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] \r",
1693 timeval_elapsed(&state->starttime),
1694 (unsigned long long)num_setups,
1695 avs_setup_latency,
1696 min_setup_latency,
1697 max_setup_latency,
1698 (unsigned long long)num_logoffs,
1699 avs_logoff_latency,
1700 min_logoff_latency,
1701 max_logoff_latency);
1702 return;
1705 avs_setup_latency = state->setups.total_latency / state->setups.num_finished;
1706 avs_logoff_latency = state->logoffs.total_latency / state->logoffs.num_finished;
1707 num_setups = state->setups.num_finished / state->timelimit;
1708 num_logoffs = state->logoffs.num_finished / state->timelimit;
1710 torture_comment(state->tctx,
1711 "%.2f second: "
1712 "setup[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
1713 "logoff[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
1714 timeval_elapsed(&state->starttime),
1715 (unsigned long long)num_setups,
1716 avs_setup_latency,
1717 state->setups.min_latency,
1718 state->setups.max_latency,
1719 (unsigned long long)num_logoffs,
1720 avs_logoff_latency,
1721 state->logoffs.min_latency,
1722 state->logoffs.max_latency);
1724 asserted:
1725 state->stop = true;
1728 static bool test_smb2_bench_session_setup(struct torture_context *tctx,
1729 struct smb2_tree *tree)
1731 struct test_smb2_bench_session_setup_shared_state *state = NULL;
1732 bool ret = true;
1733 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
1734 int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
1735 size_t i;
1736 size_t li = 0;
1737 int timelimit = torture_setting_int(tctx, "timelimit", 10);
1738 struct tevent_timer *te = NULL;
1739 uint32_t timeout_msec;
1741 state = talloc_zero(tctx, struct test_smb2_bench_session_setup_shared_state);
1742 torture_assert(tctx, state != NULL, __location__);
1743 state->tctx = tctx;
1744 state->credentials = samba_cmdline_get_creds();
1745 torture_assert(tctx, state->credentials != NULL, __location__);
1746 state->gensec_settings = lpcfg_gensec_settings(state, tctx->lp_ctx);
1747 torture_assert(tctx, state->gensec_settings != NULL, __location__);
1748 state->num_conns = torture_nprocs;
1749 state->conns = talloc_zero_array(state,
1750 struct test_smb2_bench_session_setup_shared_conn,
1751 state->num_conns);
1752 torture_assert(tctx, state->conns != NULL, __location__);
1753 state->num_loops = torture_nprocs * torture_qdepth;
1754 state->loops = talloc_zero_array(state,
1755 struct test_smb2_bench_session_setup_shared_loop,
1756 state->num_loops);
1757 torture_assert(tctx, state->loops != NULL, __location__);
1758 state->ok = true;
1759 state->timelimit = MAX(timelimit, 1);
1761 timeout_msec = tree->session->transport->options.request_timeout * 1000;
1763 torture_comment(tctx, "Opening %zd connections\n", state->num_conns);
1765 for (i=0;i<state->num_conns;i++) {
1766 struct smb2_tree *ct = NULL;
1767 DATA_BLOB out_input_buffer = data_blob_null;
1768 DATA_BLOB out_output_buffer = data_blob_null;
1769 size_t pcli;
1771 state->conns[i].state = state;
1772 state->conns[i].idx = i;
1774 if (!torture_smb2_connection(tctx, &ct)) {
1775 torture_comment(tctx, "Failed opening %zd/%zd connections\n", i, state->num_conns);
1776 return false;
1778 talloc_steal(state->conns, ct);
1779 state->conns[i].transport = ct->session->transport;
1781 smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
1782 smb2cli_ioctl(ct->session->transport->conn,
1783 timeout_msec,
1784 ct->session->smbXcli,
1785 ct->smbXcli,
1786 UINT64_MAX, /* in_fid_persistent */
1787 UINT64_MAX, /* in_fid_volatile */
1788 UINT32_MAX,
1789 0, /* in_max_input_length */
1790 NULL, /* in_input_buffer */
1791 1, /* in_max_output_length */
1792 NULL, /* in_output_buffer */
1793 SMB2_IOCTL_FLAG_IS_FSCTL,
1795 &out_input_buffer,
1796 &out_output_buffer);
1797 torture_assert(tctx,
1798 smbXcli_conn_is_connected(ct->session->transport->conn),
1799 "smbXcli_conn_is_connected");
1800 for (pcli = 0; pcli < torture_qdepth; pcli++) {
1801 struct test_smb2_bench_session_setup_shared_loop *loop = &state->loops[li];
1803 loop->idx = li++;
1804 loop->state = state;
1805 loop->conn = &state->conns[i];
1806 loop->im = tevent_create_immediate(state->loops);
1807 torture_assert(tctx, loop->im != NULL, __location__);
1809 tevent_schedule_immediate(loop->im,
1810 tctx->ev,
1811 test_smb2_bench_session_setup_loop_start,
1812 loop);
1816 torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
1817 state->num_conns, torture_qdepth, state->num_loops);
1819 torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
1821 state->starttime = timeval_current();
1823 te = tevent_add_timer(tctx->ev,
1824 state,
1825 timeval_current_ofs(1, 0),
1826 test_smb2_bench_session_setup_progress,
1827 state);
1828 torture_assert(tctx, te != NULL, __location__);
1830 while (!state->stop) {
1831 int rc = tevent_loop_once(tctx->ev);
1832 torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
1835 torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
1836 TALLOC_FREE(state);
1837 return ret;
1840 struct torture_suite *torture_smb2_bench_init(TALLOC_CTX *ctx)
1842 struct torture_suite *suite = torture_suite_create(ctx, "bench");
1844 torture_suite_add_1smb2_test(suite, "oplock1", test_smb2_bench_oplock);
1845 torture_suite_add_1smb2_test(suite, "echo", test_smb2_bench_echo);
1846 torture_suite_add_1smb2_test(suite, "path-contention-shared", test_smb2_bench_path_contention_shared);
1847 torture_suite_add_1smb2_test(suite, "read", test_smb2_bench_read);
1848 torture_suite_add_1smb2_test(suite, "session-setup", test_smb2_bench_session_setup);
1850 suite->description = talloc_strdup(suite, "SMB2-BENCH tests");
1852 return suite;