r22087: added a RAW-BENCH-OPEN test that can be used to stress out a clustered
[kai/samba-autobuild/.git] / source4 / torture / raw / openbench.c
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "torture/torture.h"
25 #include "libcli/raw/libcliraw.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
33 #define BASEDIR "\\benchopen"
34
35 static int nprocs;
36 static int open_failed;
37 static int open_retries;
38 static char **fnames;
39
40 struct benchopen_state {
41         struct smbcli_state *cli;
42         int fnum;
43         int file_num;
44         int count;
45         BOOL waiting_open, waiting_close;
46         union smb_open open_parms;
47         union smb_close close_parms;
48         struct smbcli_request *req_open;
49         struct smbcli_request *req_close;
50 };
51
52 static void open_completed(struct smbcli_request *req);
53 static void close_completed(struct smbcli_request *req);
54
55
56 static void next_open(struct benchopen_state *state)
57 {
58         state->count++;
59
60         state->file_num = (state->file_num+1) % (nprocs+1);
61         state->open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
62         state->open_parms.ntcreatex.in.flags = 0;
63         state->open_parms.ntcreatex.in.root_fid = 0;
64         state->open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
65         state->open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
66         state->open_parms.ntcreatex.in.alloc_size = 0;
67         state->open_parms.ntcreatex.in.share_access = 0;
68         state->open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
69         state->open_parms.ntcreatex.in.create_options = 0;
70         state->open_parms.ntcreatex.in.impersonation = 0;
71         state->open_parms.ntcreatex.in.security_flags = 0;
72         state->open_parms.ntcreatex.in.fname = fnames[state->file_num];
73
74         state->req_open = smb_raw_open_send(state->cli->tree, &state->open_parms);
75         state->req_open->async.fn = open_completed;
76         state->req_open->async.private = state;
77         state->waiting_open = True;
78
79         if (state->fnum == -1) {
80                 return;
81         }
82
83         state->close_parms.close.level = RAW_CLOSE_CLOSE;
84         state->close_parms.close.in.file.fnum = state->fnum;
85         state->close_parms.close.in.write_time = 0;
86
87         state->req_close = smb_raw_close_send(state->cli->tree, &state->close_parms);
88         state->req_close->async.fn = close_completed;
89         state->req_close->async.private = state;
90         state->waiting_close = True;
91 }
92
93 /*
94   called when a open completes
95 */
96 static void open_completed(struct smbcli_request *req)
97 {
98         struct benchopen_state *state = (struct benchopen_state *)req->async.private;
99         TALLOC_CTX *tmp_ctx = talloc_new(state->cli);
100         NTSTATUS status;
101
102         status = smb_raw_open_recv(req, tmp_ctx, &state->open_parms);
103
104         talloc_free(tmp_ctx);
105
106         state->req_open = NULL;
107
108         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
109                 open_retries++;
110                 state->req_open = smb_raw_open_send(state->cli->tree, &state->open_parms);
111                 state->req_open->async.fn = open_completed;
112                 state->req_open->async.private = state;
113                 return;
114         }
115
116         if (!NT_STATUS_IS_OK(status)) {
117                 open_failed++;
118                 DEBUG(0,("open failed - %s\n", nt_errstr(status)));
119                 return;
120         }
121
122         state->fnum = state->open_parms.ntcreatex.out.file.fnum;
123         state->waiting_open = False;
124
125         if (!state->waiting_close) {
126                 next_open(state);
127         }
128 }       
129
130 /*
131   called when a close completes
132 */
133 static void close_completed(struct smbcli_request *req)
134 {
135         struct benchopen_state *state = (struct benchopen_state *)req->async.private;
136         NTSTATUS status = smbcli_request_simple_recv(req);
137
138         state->req_close = NULL;
139
140         if (!NT_STATUS_IS_OK(status)) {
141                 open_failed++;
142                 DEBUG(0,("close failed - %s\n", nt_errstr(status)));
143                 return;
144         }
145
146         state->waiting_close = False;
147
148         if (!state->waiting_open) {
149                 next_open(state);
150         }
151 }       
152
153 /* 
154    benchmark open calls
155 */
156 BOOL torture_bench_open(struct torture_context *torture)
157 {
158         BOOL ret = True;
159         TALLOC_CTX *mem_ctx = talloc_new(torture);
160         int i;
161         int timelimit = torture_setting_int(torture, "timelimit", 10);
162         struct timeval tv;
163         struct event_context *ev = event_context_find(mem_ctx);
164         struct benchopen_state *state;
165         int total = 0, loops=0, minops=0;
166         
167         nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
168
169         state = talloc_zero_array(mem_ctx, struct benchopen_state, nprocs);
170
171         printf("Opening %d connections\n", nprocs);
172         for (i=0;i<nprocs;i++) {
173                 if (!torture_open_connection_ev(&state[i].cli, i, ev)) {
174                         return False;
175                 }
176                 talloc_steal(mem_ctx, state);
177         }
178
179         if (!torture_setup_dir(state[0].cli, BASEDIR)) {
180                 goto failed;
181         }
182
183         fnames = talloc_array(mem_ctx, char *, nprocs+1);
184         for (i=0;i<nprocs+1;i++) {
185                 fnames[i] = talloc_asprintf(fnames, "%s\\file%d.dat", BASEDIR, i);
186         }
187
188         for (i=0;i<nprocs;i++) {
189                 state[i].fnum = -1;
190                 state[i].file_num = i;          
191                 next_open(&state[i]);
192         }
193
194         tv = timeval_current(); 
195
196         printf("Running for %d seconds\n", timelimit);
197         while (timeval_elapsed(&tv) < timelimit) {
198                 event_loop_once(ev);
199
200                 total = 0;
201                 for (i=0;i<nprocs;i++) {
202                         total += state[i].count;
203                 }
204
205                 if (open_failed) {
206                         DEBUG(0,("open failed after %d opens\n", total));
207                         goto failed;
208                 }
209
210                 if (loops++ % 1000 != 0) continue;
211
212                 printf("%.2f ops/second (%d retries)\r", 
213                        total/timeval_elapsed(&tv), open_retries);
214                 fflush(stdout);
215         }
216
217         printf("%.2f ops/second (%d retries)\n", 
218                total/timeval_elapsed(&tv), open_retries);
219         minops = state[0].count;
220         for (i=0;i<nprocs;i++) {
221                 printf("[%d] %u ops\n", i, state[i].count);
222                 if (state[i].count < minops) minops = state[i].count;
223         }
224         if (minops < 0.5*total/nprocs) {
225                 printf("Failed: unbalanced open\n");
226                 goto failed;
227         }
228
229         for (i=0;i<nprocs;i++) {
230                 talloc_free(state[i].req_open);
231                 talloc_free(state[i].req_close);
232                 smb_raw_exit(state[i].cli->session);
233         }
234
235         smbcli_deltree(state[0].cli->tree, BASEDIR);
236         talloc_free(mem_ctx);
237         return ret;
238
239 failed:
240         for (i=0;i<nprocs;i++) {
241                 talloc_free(state[i].req_open);
242                 talloc_free(state[i].req_close);
243                 smb_raw_exit(state[i].cli->session);
244         }
245         smbcli_deltree(state[0].cli->tree, BASEDIR);
246         talloc_free(mem_ctx);
247         return False;
248 }