2007-04-05 10:23:06 +04:00
/*
Unix SMB / CIFS implementation .
open benchmark
Copyright ( C ) Andrew Tridgell 2007
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2007-04-05 10:23:06 +04:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2007-04-05 10:23:06 +04:00
*/
# include "includes.h"
# include "torture/torture.h"
# include "libcli/raw/libcliraw.h"
# include "system/time.h"
# include "system/filesys.h"
# include "libcli/libcli.h"
# include "torture/util.h"
# include "lib/events/events.h"
# include "lib/cmdline/popt_common.h"
2007-05-22 03:33:26 +04:00
# include "libcli/composite/composite.h"
# include "libcli/smb_composite/smb_composite.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2007-04-05 10:23:06 +04:00
# define BASEDIR "\\benchopen"
static int nprocs ;
static int open_failed ;
static int open_retries ;
static char * * fnames ;
2007-05-22 03:33:26 +04:00
static int num_connected ;
2007-05-26 07:24:08 +04:00
static struct timed_event * report_te ;
2007-05-22 08:53:05 +04:00
2007-04-05 10:23:06 +04:00
struct benchopen_state {
2007-05-22 03:33:26 +04:00
TALLOC_CTX * mem_ctx ;
struct event_context * ev ;
2007-04-05 10:23:06 +04:00
struct smbcli_state * cli ;
2007-05-22 03:33:26 +04:00
struct smbcli_tree * tree ;
int client_num ;
2007-05-22 08:53:05 +04:00
int old_fnum ;
2007-04-05 10:23:06 +04:00
int fnum ;
int file_num ;
int count ;
2007-05-22 03:33:26 +04:00
int lastcount ;
2007-04-05 10:23:06 +04:00
union smb_open open_parms ;
union smb_close close_parms ;
struct smbcli_request * req_open ;
struct smbcli_request * req_close ;
2007-05-22 03:33:26 +04:00
struct smb_composite_connect reconnect ;
2007-05-29 12:22:45 +04:00
struct timed_event * te ;
2007-05-22 03:33:26 +04:00
/* these are used for reconnections */
int dest_port ;
const char * dest_host ;
const char * called_name ;
const char * service_type ;
2007-04-05 10:23:06 +04:00
} ;
2007-05-22 03:33:26 +04:00
static void next_open ( struct benchopen_state * state ) ;
static void reopen_connection ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * private_data ) ;
/*
complete an async reconnect
*/
static void reopen_connection_complete ( struct composite_context * ctx )
{
struct benchopen_state * state = ( struct benchopen_state * ) ctx - > async . private_data ;
NTSTATUS status ;
struct smb_composite_connect * io = & state - > reconnect ;
status = smb_composite_connect_recv ( ctx , state - > mem_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-05-29 12:22:45 +04:00
talloc_free ( state - > te ) ;
state - > te = event_add_timed ( state - > ev , state - > mem_ctx ,
timeval_current_ofs ( 1 , 0 ) ,
reopen_connection , state ) ;
2007-05-22 03:33:26 +04:00
return ;
}
state - > tree = io - > out . tree ;
num_connected + + ;
DEBUG ( 0 , ( " reconnect to %s finished (%u connected) \n " , state - > dest_host ,
num_connected ) ) ;
2007-05-22 08:53:05 +04:00
state - > fnum = - 1 ;
2007-05-26 07:24:08 +04:00
state - > old_fnum = - 1 ;
next_open ( state ) ;
2007-05-22 03:33:26 +04:00
}
/*
reopen a connection
*/
static void reopen_connection ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * private_data )
{
struct benchopen_state * state = ( struct benchopen_state * ) private_data ;
struct composite_context * ctx ;
struct smb_composite_connect * io = & state - > reconnect ;
char * host , * share ;
2007-05-29 12:30:41 +04:00
state - > te = NULL ;
2007-05-22 03:33:26 +04:00
if ( ! torture_get_conn_index ( state - > client_num , state - > mem_ctx , & host , & share ) ) {
DEBUG ( 0 , ( " Can't find host/share for reconnect?! \n " ) ) ;
exit ( 1 ) ;
}
io - > in . dest_host = state - > dest_host ;
io - > in . port = state - > dest_port ;
io - > in . called_name = state - > called_name ;
io - > in . service = share ;
io - > in . service_type = state - > service_type ;
io - > in . credentials = cmdline_credentials ;
io - > in . fallback_to_anonymous = False ;
2007-09-28 05:17:46 +04:00
io - > in . workgroup = lp_workgroup ( global_loadparm ) ;
2007-05-22 03:33:26 +04:00
/* kill off the remnants of the old connection */
talloc_free ( state - > tree ) ;
state - > tree = NULL ;
state - > fnum = - 1 ;
ctx = smb_composite_connect_send ( io , state - > mem_ctx , state - > ev ) ;
if ( ctx = = NULL ) {
DEBUG ( 0 , ( " Failed to setup async reconnect \n " ) ) ;
exit ( 1 ) ;
}
ctx - > async . fn = reopen_connection_complete ;
ctx - > async . private_data = state ;
}
2007-04-05 10:23:06 +04:00
static void open_completed ( struct smbcli_request * req ) ;
static void close_completed ( struct smbcli_request * req ) ;
static void next_open ( struct benchopen_state * state )
{
state - > count + + ;
2007-05-26 07:24:08 +04:00
state - > file_num = ( state - > file_num + 1 ) % ( 3 * nprocs ) ;
DEBUG ( 2 , ( " [%d] opening %u \n " , state - > client_num , state - > file_num ) ) ;
2007-04-05 10:23:06 +04:00
state - > open_parms . ntcreatex . level = RAW_OPEN_NTCREATEX ;
state - > open_parms . ntcreatex . in . flags = 0 ;
state - > open_parms . ntcreatex . in . root_fid = 0 ;
state - > open_parms . ntcreatex . in . access_mask = SEC_RIGHTS_FILE_ALL ;
state - > open_parms . ntcreatex . in . file_attr = FILE_ATTRIBUTE_NORMAL ;
state - > open_parms . ntcreatex . in . alloc_size = 0 ;
state - > open_parms . ntcreatex . in . share_access = 0 ;
state - > open_parms . ntcreatex . in . open_disposition = NTCREATEX_DISP_OVERWRITE_IF ;
state - > open_parms . ntcreatex . in . create_options = 0 ;
state - > open_parms . ntcreatex . in . impersonation = 0 ;
state - > open_parms . ntcreatex . in . security_flags = 0 ;
state - > open_parms . ntcreatex . in . fname = fnames [ state - > file_num ] ;
2007-05-22 03:33:26 +04:00
state - > req_open = smb_raw_open_send ( state - > tree , & state - > open_parms ) ;
2007-04-05 10:23:06 +04:00
state - > req_open - > async . fn = open_completed ;
state - > req_open - > async . private = state ;
2007-05-22 08:53:05 +04:00
}
2007-04-05 10:23:06 +04:00
2007-05-22 08:53:05 +04:00
static void next_close ( struct benchopen_state * state )
{
2007-05-26 07:24:08 +04:00
DEBUG ( 2 , ( " [%d] closing %d \n " , state - > client_num , state - > old_fnum ) ) ;
if ( state - > old_fnum = = - 1 ) {
return ;
}
2007-04-05 10:23:06 +04:00
state - > close_parms . close . level = RAW_CLOSE_CLOSE ;
2007-05-22 08:53:05 +04:00
state - > close_parms . close . in . file . fnum = state - > old_fnum ;
2007-04-05 10:23:06 +04:00
state - > close_parms . close . in . write_time = 0 ;
2007-05-22 03:33:26 +04:00
state - > req_close = smb_raw_close_send ( state - > tree , & state - > close_parms ) ;
2007-04-05 10:23:06 +04:00
state - > req_close - > async . fn = close_completed ;
state - > req_close - > async . private = state ;
2007-05-26 07:24:08 +04:00
state - > old_fnum = - 1 ;
2007-04-05 10:23:06 +04:00
}
/*
called when a open completes
*/
static void open_completed ( struct smbcli_request * req )
{
struct benchopen_state * state = ( struct benchopen_state * ) req - > async . private ;
2007-05-22 03:33:26 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( state - > mem_ctx ) ;
2007-04-05 10:23:06 +04:00
NTSTATUS status ;
status = smb_raw_open_recv ( req , tmp_ctx , & state - > open_parms ) ;
talloc_free ( tmp_ctx ) ;
state - > req_open = NULL ;
2007-05-22 03:33:26 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_END_OF_FILE ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_LOCAL_DISCONNECT ) ) {
talloc_free ( state - > tree ) ;
talloc_free ( state - > cli ) ;
state - > tree = NULL ;
state - > cli = NULL ;
num_connected - - ;
DEBUG ( 0 , ( " reopening connection to %s \n " , state - > dest_host ) ) ;
2007-05-29 12:22:45 +04:00
talloc_free ( state - > te ) ;
state - > te = event_add_timed ( state - > ev , state - > mem_ctx ,
timeval_current_ofs ( 1 , 0 ) ,
reopen_connection , state ) ;
2007-05-22 03:33:26 +04:00
return ;
}
2007-04-05 10:23:06 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_SHARING_VIOLATION ) ) {
2007-05-26 07:24:08 +04:00
DEBUG ( 2 , ( " [%d] retrying open \n " , state - > client_num ) ) ;
2007-04-05 10:23:06 +04:00
open_retries + + ;
2007-05-22 03:33:26 +04:00
state - > req_open = smb_raw_open_send ( state - > tree , & state - > open_parms ) ;
2007-04-05 10:23:06 +04:00
state - > req_open - > async . fn = open_completed ;
state - > req_open - > async . private = state ;
return ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
open_failed + + ;
DEBUG ( 0 , ( " open failed - %s \n " , nt_errstr ( status ) ) ) ;
return ;
}
2007-05-26 07:24:08 +04:00
state - > old_fnum = state - > fnum ;
2007-04-05 10:23:06 +04:00
state - > fnum = state - > open_parms . ntcreatex . out . file . fnum ;
2007-05-26 07:24:08 +04:00
DEBUG ( 2 , ( " [%d] open completed: fnum=%d old_fnum=%d \n " ,
state - > client_num , state - > fnum , state - > old_fnum ) ) ;
if ( state - > old_fnum ! = - 1 ) {
next_close ( state ) ;
}
next_open ( state ) ;
2007-04-05 10:23:06 +04:00
}
/*
called when a close completes
*/
static void close_completed ( struct smbcli_request * req )
{
struct benchopen_state * state = ( struct benchopen_state * ) req - > async . private ;
NTSTATUS status = smbcli_request_simple_recv ( req ) ;
state - > req_close = NULL ;
2007-05-22 03:33:26 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_END_OF_FILE ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_LOCAL_DISCONNECT ) ) {
talloc_free ( state - > tree ) ;
talloc_free ( state - > cli ) ;
state - > tree = NULL ;
state - > cli = NULL ;
num_connected - - ;
DEBUG ( 0 , ( " reopening connection to %s \n " , state - > dest_host ) ) ;
2007-05-29 12:22:45 +04:00
talloc_free ( state - > te ) ;
state - > te = event_add_timed ( state - > ev , state - > mem_ctx ,
timeval_current_ofs ( 1 , 0 ) ,
reopen_connection , state ) ;
2007-05-22 03:33:26 +04:00
return ;
}
2007-04-05 10:23:06 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
open_failed + + ;
DEBUG ( 0 , ( " close failed - %s \n " , nt_errstr ( status ) ) ) ;
return ;
}
2007-05-26 07:24:08 +04:00
DEBUG ( 2 , ( " [%d] close completed: fnum=%d old_fnum=%d \n " ,
state - > client_num , state - > fnum , state - > old_fnum ) ) ;
2007-05-22 08:53:05 +04:00
}
2007-04-05 10:23:06 +04:00
2007-05-25 16:21:29 +04:00
static void echo_completion ( struct smbcli_request * req )
{
2007-08-21 05:27:21 +04:00
struct benchopen_state * state = ( struct benchopen_state * ) req - > async . private ;
2007-05-25 16:21:29 +04:00
NTSTATUS status = smbcli_request_simple_recv ( req ) ;
2007-05-29 11:32:28 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_END_OF_FILE ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_LOCAL_DISCONNECT ) ) {
2007-05-25 16:21:29 +04:00
talloc_free ( state - > tree ) ;
state - > tree = NULL ;
num_connected - - ;
DEBUG ( 0 , ( " reopening connection to %s \n " , state - > dest_host ) ) ;
2007-05-29 12:22:45 +04:00
talloc_free ( state - > te ) ;
state - > te = event_add_timed ( state - > ev , state - > mem_ctx ,
timeval_current_ofs ( 1 , 0 ) ,
reopen_connection , state ) ;
2007-05-25 16:21:29 +04:00
}
}
2007-05-22 03:33:26 +04:00
static void report_rate ( struct event_context * ev , struct timed_event * te ,
struct timeval t , void * private_data )
{
struct benchopen_state * state = talloc_get_type ( private_data ,
struct benchopen_state ) ;
int i ;
for ( i = 0 ; i < nprocs ; i + + ) {
printf ( " %5u " , ( unsigned ) ( state [ i ] . count - state [ i ] . lastcount ) ) ;
state [ i ] . lastcount = state [ i ] . count ;
}
printf ( " \r " ) ;
fflush ( stdout ) ;
2007-05-26 07:24:08 +04:00
report_te = event_add_timed ( ev , state , timeval_current_ofs ( 1 , 0 ) ,
report_rate , state ) ;
2007-05-25 14:43:06 +04:00
/* send an echo on each interface to ensure it stays alive - this helps
with IP takeover */
for ( i = 0 ; i < nprocs ; i + + ) {
struct smb_echo p ;
2007-05-25 16:21:29 +04:00
struct smbcli_request * req ;
2007-05-25 16:35:03 +04:00
if ( ! state [ i ] . tree ) {
continue ;
}
2007-05-25 16:21:29 +04:00
p . in . repeat_count = 1 ;
2007-05-25 14:43:06 +04:00
p . in . size = 0 ;
p . in . data = NULL ;
2007-05-25 16:21:29 +04:00
req = smb_raw_echo_send ( state [ i ] . tree - > session - > transport , & p ) ;
2007-08-21 05:17:13 +04:00
req - > async . private = & state [ i ] ;
2007-05-25 16:21:29 +04:00
req - > async . fn = echo_completion ;
2007-05-25 14:43:06 +04:00
}
2007-05-22 03:33:26 +04:00
}
2007-04-05 10:23:06 +04:00
/*
benchmark open calls
*/
BOOL torture_bench_open ( struct torture_context * torture )
{
BOOL ret = True ;
TALLOC_CTX * mem_ctx = talloc_new ( torture ) ;
int i ;
int timelimit = torture_setting_int ( torture , " timelimit " , 10 ) ;
struct timeval tv ;
struct event_context * ev = event_context_find ( mem_ctx ) ;
struct benchopen_state * state ;
2007-05-22 03:33:26 +04:00
int total = 0 , minops = 0 ;
2007-05-26 07:24:08 +04:00
bool progress = False ;
2007-05-22 03:33:26 +04:00
progress = torture_setting_bool ( torture , " progress " , true ) ;
2007-04-05 10:23:06 +04:00
2007-08-28 04:16:58 +04:00
nprocs = torture_setting_int ( torture , " nprocs " , 4 ) ;
2007-04-05 10:23:06 +04:00
state = talloc_zero_array ( mem_ctx , struct benchopen_state , nprocs ) ;
printf ( " Opening %d connections \n " , nprocs ) ;
for ( i = 0 ; i < nprocs ; i + + ) {
2007-05-22 03:33:26 +04:00
state [ i ] . mem_ctx = talloc_new ( state ) ;
state [ i ] . client_num = i ;
state [ i ] . ev = ev ;
2007-04-05 10:23:06 +04:00
if ( ! torture_open_connection_ev ( & state [ i ] . cli , i , ev ) ) {
return False ;
}
talloc_steal ( mem_ctx , state ) ;
2007-05-22 03:33:26 +04:00
state [ i ] . tree = state [ i ] . cli - > tree ;
state [ i ] . dest_host = talloc_strdup ( state [ i ] . mem_ctx ,
state [ i ] . cli - > tree - > session - > transport - > socket - > hostname ) ;
state [ i ] . dest_port = state [ i ] . cli - > tree - > session - > transport - > socket - > port ;
state [ i ] . called_name = talloc_strdup ( state [ i ] . mem_ctx ,
state [ i ] . cli - > tree - > session - > transport - > called . name ) ;
state [ i ] . service_type = talloc_strdup ( state [ i ] . mem_ctx ,
state [ i ] . cli - > tree - > device ) ;
2007-04-05 10:23:06 +04:00
}
2007-05-22 03:33:26 +04:00
num_connected = i ;
2007-04-05 10:23:06 +04:00
if ( ! torture_setup_dir ( state [ 0 ] . cli , BASEDIR ) ) {
goto failed ;
}
2007-05-26 07:24:08 +04:00
fnames = talloc_array ( mem_ctx , char * , 3 * nprocs ) ;
for ( i = 0 ; i < 3 * nprocs ; i + + ) {
2007-04-05 10:23:06 +04:00
fnames [ i ] = talloc_asprintf ( fnames , " %s \\ file%d.dat " , BASEDIR , i ) ;
}
for ( i = 0 ; i < nprocs ; i + + ) {
state [ i ] . file_num = i ;
2007-05-22 09:16:16 +04:00
state [ i ] . fnum = smbcli_open ( state [ i ] . tree ,
fnames [ state - > file_num ] ,
O_RDWR | O_CREAT , DENY_ALL ) ;
2007-05-26 07:24:08 +04:00
state [ i ] . old_fnum = - 1 ;
next_open ( & state [ i ] ) ;
2007-04-05 10:23:06 +04:00
}
tv = timeval_current ( ) ;
2007-05-22 03:33:26 +04:00
if ( progress ) {
2007-05-26 07:24:08 +04:00
report_te = event_add_timed ( ev , state , timeval_current_ofs ( 1 , 0 ) ,
report_rate , state ) ;
2007-05-22 03:33:26 +04:00
}
2007-04-05 10:23:06 +04:00
printf ( " Running for %d seconds \n " , timelimit ) ;
while ( timeval_elapsed ( & tv ) < timelimit ) {
event_loop_once ( ev ) ;
if ( open_failed ) {
2007-05-22 03:33:26 +04:00
DEBUG ( 0 , ( " open failed \n " ) ) ;
2007-04-05 10:23:06 +04:00
goto failed ;
}
}
2007-05-26 07:24:08 +04:00
talloc_free ( report_te ) ;
2007-04-05 10:23:06 +04:00
printf ( " %.2f ops/second (%d retries) \n " ,
total / timeval_elapsed ( & tv ) , open_retries ) ;
minops = state [ 0 ] . count ;
for ( i = 0 ; i < nprocs ; i + + ) {
printf ( " [%d] %u ops \n " , i , state [ i ] . count ) ;
if ( state [ i ] . count < minops ) minops = state [ i ] . count ;
}
if ( minops < 0.5 * total / nprocs ) {
printf ( " Failed: unbalanced open \n " ) ;
goto failed ;
}
for ( i = 0 ; i < nprocs ; i + + ) {
talloc_free ( state [ i ] . req_open ) ;
talloc_free ( state [ i ] . req_close ) ;
2007-05-22 03:33:26 +04:00
smb_raw_exit ( state [ i ] . tree - > session ) ;
2007-04-05 10:23:06 +04:00
}
2007-05-22 03:33:26 +04:00
smbcli_deltree ( state [ 0 ] . tree , BASEDIR ) ;
2007-04-05 10:23:06 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
failed :
talloc_free ( mem_ctx ) ;
return False ;
}