~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/torture/raw/openbench.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
 
 
4
   open benchmark
 
5
 
 
6
   Copyright (C) Andrew Tridgell 2007
 
7
   
 
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.
 
12
   
 
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.
 
17
   
 
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/>.
 
20
*/
 
21
 
 
22
#include "includes.h"
 
23
#include "torture/torture.h"
 
24
#include "libcli/raw/libcliraw.h"
 
25
#include "libcli/raw/raw_proto.h"
 
26
#include "system/time.h"
 
27
#include "system/filesys.h"
 
28
#include "libcli/libcli.h"
 
29
#include "torture/util.h"
 
30
#include "lib/events/events.h"
 
31
#include "lib/cmdline/popt_common.h"
 
32
#include "libcli/composite/composite.h"
 
33
#include "libcli/smb_composite/smb_composite.h"
 
34
#include "libcli/resolve/resolve.h"
 
35
#include "param/param.h"
 
36
 
 
37
#define BASEDIR "\\benchopen"
 
38
 
 
39
static int nprocs;
 
40
static int open_failed;
 
41
static int close_failed;
 
42
static char **fnames;
 
43
static int num_connected;
 
44
static struct tevent_timer *report_te;
 
45
 
 
46
struct benchopen_state {
 
47
        struct torture_context *tctx;
 
48
        TALLOC_CTX *mem_ctx;
 
49
        struct tevent_context *ev;
 
50
        struct smbcli_state *cli;
 
51
        struct smbcli_tree *tree;
 
52
        int client_num;
 
53
        int close_fnum;
 
54
        int open_fnum;
 
55
        int close_file_num;
 
56
        int open_file_num;
 
57
        int pending_file_num;
 
58
        int next_file_num;
 
59
        int count;
 
60
        int lastcount;
 
61
        union smb_open open_parms;
 
62
        int open_retries;
 
63
        union smb_close close_parms;
 
64
        struct smbcli_request *req_open;
 
65
        struct smbcli_request *req_close;
 
66
        struct smb_composite_connect reconnect;
 
67
        struct tevent_timer *te;
 
68
 
 
69
        /* these are used for reconnections */
 
70
        const char **dest_ports;
 
71
        const char *dest_host;
 
72
        const char *called_name;
 
73
        const char *service_type;
 
74
};
 
75
 
 
76
static void next_open(struct benchopen_state *state);
 
77
static void reopen_connection(struct tevent_context *ev, struct tevent_timer *te, 
 
78
                              struct timeval t, void *private_data);
 
79
 
 
80
 
 
81
/*
 
82
  complete an async reconnect
 
83
 */
 
84
static void reopen_connection_complete(struct composite_context *ctx)
 
85
{
 
86
        struct benchopen_state *state = (struct benchopen_state *)ctx->async.private_data;
 
87
        NTSTATUS status;
 
88
        struct smb_composite_connect *io = &state->reconnect;
 
89
 
 
90
        status = smb_composite_connect_recv(ctx, state->mem_ctx);
 
91
        if (!NT_STATUS_IS_OK(status)) {
 
92
                talloc_free(state->te);
 
93
                state->te = event_add_timed(state->ev, state->mem_ctx, 
 
94
                                            timeval_current_ofs(1,0), 
 
95
                                            reopen_connection, state);
 
96
                return;
 
97
        }
 
98
 
 
99
        state->tree = io->out.tree;
 
100
 
 
101
        num_connected++;
 
102
 
 
103
        DEBUG(0,("[%u] reconnect to %s finished (%u connected)\n",
 
104
                 state->client_num, state->dest_host, num_connected));
 
105
 
 
106
        state->open_fnum = -1;
 
107
        state->close_fnum = -1;
 
108
        next_open(state);
 
109
}
 
110
 
 
111
        
 
112
 
 
113
/*
 
114
  reopen a connection
 
115
 */
 
116
static void reopen_connection(struct tevent_context *ev, struct tevent_timer *te, 
 
117
                              struct timeval t, void *private_data)
 
118
{
 
119
        struct benchopen_state *state = (struct benchopen_state *)private_data;
 
120
        struct composite_context *ctx;
 
121
        struct smb_composite_connect *io = &state->reconnect;
 
122
        char *host, *share;
 
123
 
 
124
        state->te = NULL;
 
125
 
 
126
        if (!torture_get_conn_index(state->client_num, state->mem_ctx, state->tctx, &host, &share)) {
 
127
                DEBUG(0,("Can't find host/share for reconnect?!\n"));
 
128
                exit(1);
 
129
        }
 
130
 
 
131
        io->in.dest_host    = state->dest_host;
 
132
        io->in.dest_ports   = state->dest_ports;
 
133
        io->in.socket_options = lp_socket_options(state->tctx->lp_ctx);
 
134
        io->in.called_name  = state->called_name;
 
135
        io->in.service      = share;
 
136
        io->in.service_type = state->service_type;
 
137
        io->in.credentials  = cmdline_credentials;
 
138
        io->in.fallback_to_anonymous = false;
 
139
        io->in.workgroup    = lp_workgroup(state->tctx->lp_ctx);
 
140
        io->in.gensec_settings = lp_gensec_settings(state->mem_ctx, state->tctx->lp_ctx);
 
141
        lp_smbcli_options(state->tctx->lp_ctx, &io->in.options);
 
142
        lp_smbcli_session_options(state->tctx->lp_ctx, &io->in.session_options);
 
143
 
 
144
        /* kill off the remnants of the old connection */
 
145
        talloc_free(state->tree);
 
146
        state->tree = NULL;
 
147
        state->open_fnum = -1;
 
148
        state->close_fnum = -1;
 
149
 
 
150
        ctx = smb_composite_connect_send(io, state->mem_ctx, 
 
151
                                         lp_resolve_context(state->tctx->lp_ctx), 
 
152
                                         state->ev);
 
153
        if (ctx == NULL) {
 
154
                DEBUG(0,("Failed to setup async reconnect\n"));
 
155
                exit(1);
 
156
        }
 
157
 
 
158
        ctx->async.fn = reopen_connection_complete;
 
159
        ctx->async.private_data = state;
 
160
}
 
161
 
 
162
static void open_completed(struct smbcli_request *req);
 
163
static void close_completed(struct smbcli_request *req);
 
164
 
 
165
 
 
166
static void next_open(struct benchopen_state *state)
 
167
{
 
168
        state->count++;
 
169
 
 
170
        state->pending_file_num = state->next_file_num;
 
171
        state->next_file_num = (state->next_file_num+1) % (3*nprocs);
 
172
 
 
173
        DEBUG(2,("[%d] opening %u\n", state->client_num, state->pending_file_num));
 
174
        state->open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
 
175
        state->open_parms.ntcreatex.in.flags = 0;
 
176
        state->open_parms.ntcreatex.in.root_fid = 0;
 
177
        state->open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
 
178
        state->open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
 
179
        state->open_parms.ntcreatex.in.alloc_size = 0;
 
180
        state->open_parms.ntcreatex.in.share_access = 0;
 
181
        state->open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
 
182
        state->open_parms.ntcreatex.in.create_options = 0;
 
183
        state->open_parms.ntcreatex.in.impersonation = 0;
 
184
        state->open_parms.ntcreatex.in.security_flags = 0;
 
185
        state->open_parms.ntcreatex.in.fname = fnames[state->pending_file_num];
 
186
 
 
187
        state->req_open = smb_raw_open_send(state->tree, &state->open_parms);
 
188
        state->req_open->async.fn = open_completed;
 
189
        state->req_open->async.private_data = state;
 
190
}
 
191
 
 
192
 
 
193
static void next_close(struct benchopen_state *state)
 
194
{
 
195
        if (state->close_fnum == -1) {
 
196
                return;
 
197
        }
 
198
        DEBUG(2,("[%d] closing %d (fnum[%d])\n",
 
199
                 state->client_num, state->close_file_num, state->close_fnum));
 
200
        state->close_parms.close.level = RAW_CLOSE_CLOSE;
 
201
        state->close_parms.close.in.file.fnum = state->close_fnum;
 
202
        state->close_parms.close.in.write_time = 0;
 
203
 
 
204
        state->req_close = smb_raw_close_send(state->tree, &state->close_parms);
 
205
        state->req_close->async.fn = close_completed;
 
206
        state->req_close->async.private_data = state;
 
207
}
 
208
 
 
209
/*
 
210
  called when a open completes
 
211
*/
 
212
static void open_completed(struct smbcli_request *req)
 
213
{
 
214
        struct benchopen_state *state = (struct benchopen_state *)req->async.private_data;
 
215
        TALLOC_CTX *tmp_ctx = talloc_new(state->mem_ctx);
 
216
        NTSTATUS status;
 
217
 
 
218
        status = smb_raw_open_recv(req, tmp_ctx, &state->open_parms);
 
219
 
 
220
        talloc_free(tmp_ctx);
 
221
 
 
222
        state->req_open = NULL;
 
223
 
 
224
        if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
 
225
            NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT)) {
 
226
                talloc_free(state->tree);
 
227
                talloc_free(state->cli);
 
228
                state->tree = NULL;
 
229
                state->cli = NULL;
 
230
                num_connected--;        
 
231
                DEBUG(0,("[%u] reopening connection to %s\n",
 
232
                         state->client_num, state->dest_host));
 
233
                talloc_free(state->te);
 
234
                state->te = event_add_timed(state->ev, state->mem_ctx, 
 
235
                                            timeval_current_ofs(1,0), 
 
236
                                            reopen_connection, state);
 
237
                return;
 
238
        }
 
239
 
 
240
        if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
 
241
                DEBUG(2,("[%d] retrying open %d\n",
 
242
                         state->client_num, state->pending_file_num));
 
243
                state->open_retries++;
 
244
                state->req_open = smb_raw_open_send(state->tree, &state->open_parms);
 
245
                state->req_open->async.fn = open_completed;
 
246
                state->req_open->async.private_data = state;
 
247
                return;
 
248
        }
 
249
 
 
250
        if (!NT_STATUS_IS_OK(status)) {
 
251
                open_failed++;
 
252
                DEBUG(0,("[%u] open failed %d - %s\n",
 
253
                         state->client_num, state->pending_file_num,
 
254
                         nt_errstr(status)));
 
255
                return;
 
256
        }
 
257
 
 
258
        state->close_file_num = state->open_file_num;
 
259
        state->close_fnum = state->open_fnum;
 
260
        state->open_file_num = state->pending_file_num;
 
261
        state->open_fnum = state->open_parms.ntcreatex.out.file.fnum;
 
262
 
 
263
        DEBUG(2,("[%d] open completed %d (fnum[%d])\n",
 
264
                 state->client_num, state->open_file_num, state->open_fnum));
 
265
 
 
266
        if (state->close_fnum != -1) {
 
267
                next_close(state);
 
268
        }
 
269
 
 
270
        next_open(state);
 
271
}       
 
272
 
 
273
/*
 
274
  called when a close completes
 
275
*/
 
276
static void close_completed(struct smbcli_request *req)
 
277
{
 
278
        struct benchopen_state *state = (struct benchopen_state *)req->async.private_data;
 
279
        NTSTATUS status = smbcli_request_simple_recv(req);
 
280
 
 
281
        state->req_close = NULL;
 
282
 
 
283
        if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
 
284
            NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT)) {
 
285
                talloc_free(state->tree);
 
286
                talloc_free(state->cli);
 
287
                state->tree = NULL;
 
288
                state->cli = NULL;
 
289
                num_connected--;        
 
290
                DEBUG(0,("[%u] reopening connection to %s\n",
 
291
                         state->client_num, state->dest_host));
 
292
                talloc_free(state->te);
 
293
                state->te = event_add_timed(state->ev, state->mem_ctx, 
 
294
                                            timeval_current_ofs(1,0), 
 
295
                                            reopen_connection, state);
 
296
                return;
 
297
        }
 
298
 
 
299
        if (!NT_STATUS_IS_OK(status)) {
 
300
                close_failed++;
 
301
                DEBUG(0,("[%u] close failed %d (fnum[%d]) - %s\n",
 
302
                         state->client_num, state->close_file_num,
 
303
                         state->close_fnum,
 
304
                         nt_errstr(status)));
 
305
                return;
 
306
        }
 
307
 
 
308
        DEBUG(2,("[%d] close completed %d (fnum[%d])\n",
 
309
                 state->client_num, state->close_file_num,
 
310
                 state->close_fnum));
 
311
}       
 
312
 
 
313
static void echo_completion(struct smbcli_request *req)
 
314
{
 
315
        struct benchopen_state *state = (struct benchopen_state *)req->async.private_data;
 
316
        NTSTATUS status = smbcli_request_simple_recv(req);
 
317
        if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
 
318
            NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT)) {
 
319
                talloc_free(state->tree);
 
320
                state->tree = NULL;
 
321
                num_connected--;        
 
322
                DEBUG(0,("[%u] reopening connection to %s\n",
 
323
                         state->client_num, state->dest_host));
 
324
                talloc_free(state->te);
 
325
                state->te = event_add_timed(state->ev, state->mem_ctx, 
 
326
                                            timeval_current_ofs(1,0), 
 
327
                                            reopen_connection, state);
 
328
        }
 
329
}
 
330
 
 
331
static void report_rate(struct tevent_context *ev, struct tevent_timer *te, 
 
332
                        struct timeval t, void *private_data)
 
333
{
 
334
        struct benchopen_state *state = talloc_get_type(private_data, 
 
335
                                                        struct benchopen_state);
 
336
        int i;
 
337
        for (i=0;i<nprocs;i++) {
 
338
                printf("%5u ", (unsigned)(state[i].count - state[i].lastcount));
 
339
                state[i].lastcount = state[i].count;
 
340
        }
 
341
        printf("\r");
 
342
        fflush(stdout);
 
343
        report_te = event_add_timed(ev, state, timeval_current_ofs(1, 0), 
 
344
                                    report_rate, state);
 
345
 
 
346
        /* send an echo on each interface to ensure it stays alive - this helps
 
347
           with IP takeover */
 
348
        for (i=0;i<nprocs;i++) {
 
349
                struct smb_echo p;
 
350
                struct smbcli_request *req;
 
351
 
 
352
                if (!state[i].tree) {
 
353
                        continue;
 
354
                }
 
355
 
 
356
                p.in.repeat_count = 1;
 
357
                p.in.size = 0;
 
358
                p.in.data = NULL;
 
359
                req = smb_raw_echo_send(state[i].tree->session->transport, &p);
 
360
                req->async.private_data = &state[i];
 
361
                req->async.fn      = echo_completion;
 
362
        }
 
363
}
 
364
 
 
365
/* 
 
366
   benchmark open calls
 
367
*/
 
368
bool torture_bench_open(struct torture_context *torture)
 
369
{
 
370
        bool ret = true;
 
371
        TALLOC_CTX *mem_ctx = talloc_new(torture);
 
372
        int i;
 
373
        int timelimit = torture_setting_int(torture, "timelimit", 10);
 
374
        struct timeval tv;
 
375
        struct benchopen_state *state;
 
376
        int total = 0;
 
377
        int total_retries = 0;
 
378
        int minops = 0;
 
379
        bool progress=false;
 
380
 
 
381
        progress = torture_setting_bool(torture, "progress", true);
 
382
        
 
383
        nprocs = torture_setting_int(torture, "nprocs", 4);
 
384
 
 
385
        state = talloc_zero_array(mem_ctx, struct benchopen_state, nprocs);
 
386
 
 
387
        printf("Opening %d connections\n", nprocs);
 
388
        for (i=0;i<nprocs;i++) {
 
389
                state[i].tctx = torture;
 
390
                state[i].mem_ctx = talloc_new(state);
 
391
                state[i].client_num = i;
 
392
                state[i].ev = torture->ev;
 
393
                if (!torture_open_connection_ev(&state[i].cli, i, torture, torture->ev)) {
 
394
                        return false;
 
395
                }
 
396
                talloc_steal(mem_ctx, state);
 
397
                state[i].tree = state[i].cli->tree;
 
398
                state[i].dest_host = talloc_strdup(state[i].mem_ctx, 
 
399
                                                   state[i].cli->tree->session->transport->socket->hostname);
 
400
                state[i].dest_ports = talloc_array(state[i].mem_ctx, 
 
401
                                                   const char *, 2);
 
402
                state[i].dest_ports[0] = talloc_asprintf(state[i].dest_ports, 
 
403
                                                         "%u", state[i].cli->tree->session->transport->socket->port);
 
404
                state[i].dest_ports[1] = NULL;
 
405
                state[i].called_name  = talloc_strdup(state[i].mem_ctx,
 
406
                                                      state[i].cli->tree->session->transport->called.name);
 
407
                state[i].service_type = talloc_strdup(state[i].mem_ctx,
 
408
                                                      state[i].cli->tree->device);
 
409
        }
 
410
 
 
411
        num_connected = i;
 
412
 
 
413
        if (!torture_setup_dir(state[0].cli, BASEDIR)) {
 
414
                goto failed;
 
415
        }
 
416
 
 
417
        fnames = talloc_array(mem_ctx, char *, 3*nprocs);
 
418
        for (i=0;i<3*nprocs;i++) {
 
419
                fnames[i] = talloc_asprintf(fnames, "%s\\file%d.dat", BASEDIR, i);
 
420
        }
 
421
 
 
422
        for (i=0;i<nprocs;i++) {
 
423
                /* all connections start with the same file */
 
424
                state[i].next_file_num = 0;
 
425
                state[i].open_fnum = -1;
 
426
                state[i].close_fnum = -1;
 
427
                next_open(&state[i]);
 
428
        }
 
429
 
 
430
        tv = timeval_current(); 
 
431
 
 
432
        if (progress) {
 
433
                report_te = event_add_timed(torture->ev, state, timeval_current_ofs(1, 0), 
 
434
                                            report_rate, state);
 
435
        }
 
436
 
 
437
        printf("Running for %d seconds\n", timelimit);
 
438
        while (timeval_elapsed(&tv) < timelimit) {
 
439
                event_loop_once(torture->ev);
 
440
 
 
441
                if (open_failed) {
 
442
                        DEBUG(0,("open failed\n"));
 
443
                        goto failed;
 
444
                }
 
445
                if (close_failed) {
 
446
                        DEBUG(0,("open failed\n"));
 
447
                        goto failed;
 
448
                }
 
449
        }
 
450
 
 
451
        talloc_free(report_te);
 
452
        if (progress) {
 
453
                for (i=0;i<nprocs;i++) {
 
454
                        printf("      ");
 
455
                }
 
456
                printf("\r");
 
457
        }
 
458
 
 
459
        minops = state[0].count;
 
460
        for (i=0;i<nprocs;i++) {
 
461
                total += state[i].count;
 
462
                total_retries += state[i].open_retries;
 
463
                printf("[%d] %u ops (%u retries)\n",
 
464
                       i, state[i].count, state[i].open_retries);
 
465
                if (state[i].count < minops) minops = state[i].count;
 
466
        }
 
467
        printf("%.2f ops/second (%d retries)\n",
 
468
               total/timeval_elapsed(&tv), total_retries);
 
469
        if (minops < 0.5*total/nprocs) {
 
470
                printf("Failed: unbalanced open\n");
 
471
                goto failed;
 
472
        }
 
473
 
 
474
        for (i=0;i<nprocs;i++) {
 
475
                talloc_free(state[i].req_open);
 
476
                talloc_free(state[i].req_close);
 
477
                smb_raw_exit(state[i].tree->session);
 
478
        }
 
479
 
 
480
        smbcli_deltree(state[0].tree, BASEDIR);
 
481
        talloc_free(mem_ctx);
 
482
        return ret;
 
483
 
 
484
failed:
 
485
        talloc_free(mem_ctx);
 
486
        return false;
 
487
}