function Start()
// (c) Wolfgang Riedmann 1994-2001
// http://www.riedmann.it

	local hResult
	local cDatabase
	local nArea
	local nStart
	local nStartTotal
	local cNewLine
	local aStruct
	local nMax
	local nI
	local cBuffer
	local cResult

	// prepare log file and database
	? "XBPerf - measure the xBase performance. (c) Wolfgang Riedmann 1994-2001"
	nMax			:= 50000
	cBuffer			:= ""
	for nI := 1 to 100
		cBuffer			+= chr( nI + 32 )
	next
	cNewLine		:= chr( 13 ) + chr( 10 )
	hResult			:= FOpen( "XBPerf.log", 2 )		// FO_READWRITE
	if FError() != 0
		hResult			:= FCreate( "XBPerf.log" )
	else
		FSeek( hResult, 0, 2 )		// FS_END
	endif
	FErase( "XBPERF.DBF" )
	FErase( "XBPERF.CDX" )
	aStruct			:= {}
	AAdd( aStruct, { "FIELD1", "C", 20, 0 } )
	AAdd( aStruct, { "FIELD2", "N", 10, 0 } )
	AAdd( aStruct, { "FIELD3", "C", 100, 0 } )
	DBCreate( "XBPerf.DBF", aStruct, "DBFCDX", .t., "XBPERF" )
	if Select( "XBPERF" ) > 0
		XBPERF->( DBCloseArea() )
	endif
	DBUseArea( .t., "DBFCDX", "XBPerf.DBF", "XBPERF", .t., .f. )

	nStart			:= Seconds()
	nStartTotal		:= nStart
	cResult			:= "Start " + DToC( Today() ) + " " + Time()
	FWrite( hResult, cNewLine + cResult + cNewLine )
	? cResult

	// test the append performance without index
	for nI := 1 to nMax
		XBPERF->( DBAppend() )
		XBPERF->( FieldPut( 1, Str( nI, 10 ) + Str( nMax - nI, 10 ) ) )
		XBPERF->( FieldPut( 2, nI ) )
		XBPERF->( FieldPut( 3, cBuffer ) )
		XBPERF->( DBCommit() )
	next
	cResult			:= "Append of " + AllTrim( Str( nMax, 10 ) ) + " records:" + Str( Seconds() - nStart, 10, 2 ) + " seconds"
	FWrite( hResult, cResult + cNewLine )
	? cResult
	XBPERF->( DBCloseArea() )
	DBUseArea( .t., "DBFCDX", "XBPerf.DBF", "XBPERF", .f., .f. )		// open exclusive

	// reindex performance
	nStart			:= Seconds()
	XBPERF->( OrdCreate( "XBPerf.CDX", "ORDER1", "FIELD1", {|| _FIELD->FIELD1 } ) )
	XBPERF->( OrdCreate( "XBPerf.CDX", "ORDER2", "STR(FIELD2,10)", {|| Str(_FIELD->FIELD2, 10 ) } ) )
	XBPERF->( OrdCreate( "XBPerf.CDX", "ORDER3", "FIELD3+STR(RECNO(),10)", {|| _FIELD->FIELD3 + Str( Recno(), 10 ) } ) )
	cResult			:= "Reindex of " + AllTrim( Str( nMax, 10 ) ) + " records:" + Str( Seconds() - nStart, 10, 2 ) + " seconds"
	FWrite( hResult, cResult + cNewLine )
	? cResult
	XBPERF->( DBCloseArea() )
	DBUseArea( .t., "DBFCDX", "XBPerf.DBF", "XBPERF", .t., .f. )		// open shared
//	XBPERF->( OrdListAdd( "XBPERF.CDX" ) )

	// seek performance
	XBPERF->( OrdSetFocus( "ORDER2" ) )
	nStart			:= Seconds()
	for nI := 1 to nMax
		XBPERF->( DBSeek( Str( ( Seconds() * nMax * nI ) % nMax, 10, 0 ), .f. ) )
		cResult			:= XBPERF->FIELD3
	next
	cResult			:= "Seek of " + AllTrim( Str( nMax, 10 ) ) + " records:" + Str( Seconds() - nStart, 10, 2 ) + " seconds"
	FWrite( hResult, cResult + cNewLine )
	? cResult
	XBPERF->( OrdSetFocus( "ORDER2" ) )
	XBPERF->( DBGoTop() )

	// update with change of key value
	nStart			:= Seconds()
	while ! XBPERF->( EOF() )
		XBPERF->( RLock() )
		XBPERF->( FieldPut( 1, Str( nMax - Recno(), 10 ) + Str( Recno(), 10 ) ) )
		XBPERF->( DBUnlock() )
		XBPERF->( DBSkip( 1 ) )
	end
	cResult			:= "Update of " + AllTrim( Str( nMax, 10 ) ) + " records:" + Str( Seconds() - nStart, 10, 2 ) + " seconds"
	FWrite( hResult, cResult + cNewLine )
	? cResult
	XBPERF->( OrdSetFocus( 0 ) )
	XBPERF->( DBGoTop() )

	// sequential read in natural order
	nStart			:= Seconds()
	while ! XBPERF->( EOF() )
		cResult				:= XBPERF->FIELD2
		XBPERF->( DBSkip( 1 ) )
	end
	cResult			:= "Sequential read of " + AllTrim( Str( nMax, 10 ) ) + " records:" + Str( Seconds() - nStart, 10, 2 ) + " seconds"
	FWrite( hResult, cResult + cNewLine )
	? cResult

	XBPERF->( OrdSetFocus( "ORDER2" ) )
	XBPERF->( DBGoTop() )

	// sequential read in index order
	nStart			:= Seconds()
	while ! XBPERF->( EOF() )
		cResult				:= XBPERF->FIELD2
		XBPERF->( DBSkip( 1 ) )
	end
	cResult			:= "Index read of " + AllTrim( Str( nMax, 10 ) ) + " records:" + Str( Seconds() - nStart, 10, 2 ) + " seconds"
	FWrite( hResult, cResult + cNewLine )
	? cResult

	cResult			:= cNewLine + "Total time used for " + AllTrim( Str( nMax, 10 ) ) + " records:" + ;
				Str( Seconds() - nStartTotal, 10, 2 ) + " seconds"
	FWrite( hResult, cResult + cNewLine )
	? cResult

	XBPERF->( DBCloseArea() )
	FClose( hResult )

	return nil
