Files
harbour-core/harbour/tests/speedtst.prg
Viktor Szakats 45a114e471 2010-06-03 18:17 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
* tests/testsha1.prg
  * tests/longdev.prg
  * tests/clsccast.prg
  * tests/cmphello.prg
  * tests/clsicast.prg
  * tests/testop.prg
  * tests/clsscast.prg
  * tests/objarr.prg
  * tests/rddtest/rddmktst.prg
  * tests/rddtest/adscl52.prg
  * tests/rddtest/adscl53.prg
  * tests/rddtest/ntxcl52.prg
  * tests/rddtest/ntxcl53.prg
  * tests/rddtest/cdxcl52.prg
  * tests/rddtest/rddtst.prg
  * tests/rddtest/cdxcl53.prg
  * tests/transtst.prg
  * tests/output.prg
  * tests/ac_test2.prg
  * tests/clsscope.prg
  * tests/dosshell.prg
  * tests/sbartest.prg
  * tests/speedold.prg
  * tests/sdf_test.prg
  * tests/wcecon.prg
  * tests/debugtst.prg
  * tests/testdyn.c
  * tests/multiarg.prg
  * tests/fornext.prg
  * tests/hbinline.prg
  * tests/foreach2.prg
  * tests/objasign.prg
  * tests/scroll.prg
  * tests/inherit.prg
  * tests/rto_get.prg
  * tests/boxtst2.prg
  * tests/inkeytst.prg
  * tests/overload.prg
  * tests/cpinfo.prg
  * tests/gtwin.prg
  * tests/mt/mttest08.prg
  * tests/mt/mttest09.prg
  * tests/mt/mttest01.prg
  * tests/mt/mttest10.prg
  * tests/mt/mttest02.prg
  * tests/mt/mttest11.prg
  * tests/mt/mttest03.prg
  * tests/mt/mttest12.prg
  * tests/mt/mttest04.prg
  * tests/mt/mttest05.prg
  * tests/mt/mttest06.prg
  * tests/mt/mttest07.prg
  * tests/speedtst.prg
  * tests/testsha2.prg
  * tests/hsxtest.prg
  * tests/arrayidx.prg
  * tests/clsnv.prg
  * tests/rto_tb.prg
  * tests/gtchars.prg
  * tests/disptest.prg
  * tests/funcarr.prg
  * tests/testhtml.prg
  * tests/readhrb.prg
  * tests/tstcolor.prg
  * tests/gtxfnt.prg
  * tests/devtest.prg
  * tests/aliaslck.prg
  * tests/stripem.prg
  * tests/dynobj.prg
  * tests/tb1.prg
  * tests/round.prg
  * tests/longstr.prg
  * tests/testdyn.prg
  * tests/testdyn1.prg
  * tests/delimtst.prg
  * tests/tstdspac.prg
  * tests/version.prg
  * tests/setkeys.prg
  * tests/gtcolors.prg
  * tests/destruct.prg
  * tests/seconds.prg
  * tests/gtkeys.prg
  * tests/usrrdd/exarr.prg
  * doc/en/diskspac.txt
  * doc/en/string.txt
  * doc/en/rdd.txt
  * doc/en/hashes.txt
  * doc/en/hb_apigt.txt
  * doc/en/rddord.txt
  * doc/en/hb_api.txt
  * doc/en/hb_date.txt
  * doc/en/math.txt
  * doc/en/hb_vm.txt
  * doc/en/treport.txt
  * doc/en/terminal.txt
  * doc/en/hb_apiln.txt
  * doc/en/dir.txt
  * doc/en/command.txt
  * doc/en/rddmisc.txt
  * doc/en/errsys.txt
  * doc/en/nation.txt
  * doc/en/var.txt
  * doc/en/dbstrux.txt
  * doc/en/datetime.txt
  * doc/en/memo.txt
  * doc/en/tgetlist.txt
  * doc/en/tlabel.txt
  * doc/en/1stread.txt
  * doc/en/hb_set.txt
  * doc/en/hb_compa.txt
  * doc/en/hb_apier.txt
  * doc/en/hbinet.txt
  * doc/en/hb_macro.txt
  * doc/en/array.txt
  * doc/en/hb_apiit.txt
  * doc/en/rdddb.txt
  * doc/en/dbsdf.txt
  * doc/en/hvm.txt
  * doc/en/input.txt
  * doc/en/dbdelim.txt
  * doc/en/browse.txt
  * doc/en/menu.txt
  * doc/en/hb_apird.txt
  * doc/en/hb_apifs.txt
  * doc/en/file.txt
  * doc/en/lang.txt
  * doc/en/objfunc.txt
  * doc/en/eval.txt
  * doc/en/binnum.txt
  * doc/en/tclass.txt
  * doc/en/misc.txt
  * doc/en/set.txt
  * doc/en/readme.txt
  * doc/man/harbour.1
  * doc/man/hbmk2.1
  * doc/man/hbpp.1
  * doc/man/hbtest.1
  * doc/man/hbrun.1
  * examples/hbextern/hbextern.prg
  * examples/pp/pp.c
  * examples/pp/hbpragma.c
  * examples/pp/hbppcore.c
  * examples/pp/hbppcomp.c
  * examples/pp/hbpptbl.c
  * examples/pp/hbppdef.h
  * examples/superlib/hbsuper.prg
  * examples/hbsqlit2/hbsqlit2.ch
  * examples/misc/mankala.prg
  * examples/misc/guess.prg
  * examples/rddado/adordd.prg
  * examples/rddado/adordd.ch
  * examples/hbapollo/apollo.ch
  * examples/hbapollo/apollo.c
  * examples/hbapollo/apollo1.prg
  * examples/hbdoc2/gentpl.prg
  * examples/hbdoc2/gentxt.prg
  * examples/hbdoc2/tmplates.prg
  * examples/hbdoc2/genxml.prg
  * examples/hbdoc2/genhtml.prg
  * examples/hbdoc2/hbdoc2.prg
  * examples/hbdoc2/hbdoc2.ch
  * examples/guestbk/guestbk.prg
  * examples/httpsrv/uhttpd.ini
  * examples/httpsrv/uhttpd.prg
  * examples/httpsrv/cookie.prg
  * examples/httpsrv/cgifunc.prg
  * examples/httpsrv/session.prg
  * examples/terminal/trm_cli.prg
  * examples/terminal/terminal.prg
  * examples/terminal/trm_srv.prg
  * examples/terminal/trm_app.prg
  * examples/hbbtree/hb_btree.h
  * examples/hbbtree/hb_btree.ch
  * examples/hbbtree/hb_btree.c
  * examples/hbbtree/tbtree.prg
  * examples/hscript/hscript.prg
  * examples/hscript/dir.hs
  * examples/hscript/multiply.hs
  * examples/hscript/ugly.hs
  * examples/hscript/hello.hs
  * examples/gtwvw/hbole.h
  * examples/gtwvw/wvwdraw.c
  * examples/gtwvw/wvwmenu.c
  * examples/gtwvw/gtwvw.c
  * examples/gtwvw/wvwstbar.c
  * examples/gtwvw/wvwcheck.c
  * examples/gtwvw/wvwfuncs.c
  * examples/gtwvw/wvwpush.c
  * examples/gtwvw/wvwedit.c
  * examples/gtwvw/wvwtbar.c
  * examples/gtwvw/hbgtwvw.h
    * Deleted 'www.' from harbour-project.org website name.
      (www.harbour-project.org -> harbour-project.org)
2010-06-03 16:23:36 +00:00

1034 lines
26 KiB
Plaintext

/*
* $Id$
*/
/*
* Harbour Project source code:
* HVM speed test program
*
* Copyright 2008 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* www - http://harbour-project.org
*
*/
/* Harbour MT functions used in this test */
/*
#xtranslate hb_mutexSubscribe( => mt_mutexSubscribe(
#xtranslate hb_mutexNotify( => mt_mutexNotify(
#xtranslate hb_mutexCreate( => mt_mutexCreate(
#xtranslate hb_threadOnce( => mt_threadOnce(
#xtranslate hb_threadStart( => mt_threadStart(
#xtranslate hb_threadJoin( => mt_threadJoin(
#xtranslate hb_threadWaitForAll( => mt_threadWaitForAll(
*/
#define N_TESTS 56
#define N_LOOPS 1000000
#define ARR_LEN 16
#ifndef __HARBOUR__
#ifndef __XPP__
#ifndef __CLIP__
#ifndef FlagShip
#define __CLIPPER__
#endif
#endif
#endif
#endif
#ifdef __CLIPPER__
/* Clipper does not support multithreading */
#ifndef __ST__
#define __ST__
#endif
/* Clipper does not have function to extract process time */
#xtranslate hb_secondsCPU([<x>]) => seconds()
#endif
#ifdef FlagShip
#define __NO_OBJ_ARRAY__
/* FlagShip does not support multithreading */
#ifndef __ST__
#define __ST__
#endif
#xtranslate hb_secondsCPU([<x>]) => secondsCPU(<x>)
/* the FlagShip version of seconds() returns integer values */
#xtranslate seconds() => fs_seconds()
#endif
#ifdef __XPP__
#define __NO_OBJ_ARRAY__
/* Has xBase++ function to extract process time? */
#xtranslate hb_secondsCPU([<x>]) => seconds()
#endif
#ifdef __CLIP__
#define __NO_OBJ_ARRAY__
/* CLIP version for MT performance testing is not ready yet */
#ifndef __ST__
#define __ST__
#endif
#xtranslate hb_secondsCPU([<x>]) => secondsCPU(<x>)
#endif
#ifdef __XHARBOUR__
/* By default build xHarbour binaries without MT support.
* xHarbour needs separated source code versions for MT and ST mode
* because standard MT functions are not available in ST libraries.
*/
#ifndef __ST__
#ifndef __MT__
#ifndef MT
#ifndef HB_THREAD_SUPPORT
#define __ST__
#endif
#endif
#endif
#endif
#xtranslate hb_secondsCPU([<x>]) => secondsCPU(<x>)
#endif
/* by default create MT version */
#ifndef __MT__
#ifndef __ST__
#define __MT__
#endif
#endif
#command ? => spd_out()
#command ? <xx,...> => spd_out();spd_out(<xx>)
#command ?? <xx,...> => spd_out(<xx>)
#ifdef __HARBOUR__
#define EOL hb_OSNewLine()
#else
#ifndef EOL
#define EOL chr(10)
#endif
#endif
#xcommand TEST <testfunc> ;
[ WITH <locals,...> ] ;
[ STATIC <statics,...> ] ;
[ FIELD <fields,...> ] ;
[ MEMVAR <memvars,...> ] ;
[ PRIVATE <privates,...> ] ;
[ PUBLIC <publics,...> ] ;
[ INIT <init> ] ;
[ EXIT <exit> ] ;
[ INFO <info> ] ;
CODE [ <testExp,...> ] => ;
func <testfunc> ; ;
local time, i:=nil, x:=nil ; ;
[ local <locals> ; ] ;
[ static <statics> ; ] ;
[ field <fields> ; ] ;
[ memvar <memvars> ; ] ;
[ private <privates> ; ] ;
[ public <publics> ; ] ;
[ <init> ; ] ;
time := hb_secondsCPU() ; ;
for i:=1 to N_LOOPS ; ;
[ ( <testExp> ) ; ] ;
next ; ;
time := hb_secondsCPU() - time ; ;
[ <exit> ; ] ;
return { procname() + ": " + iif( <.info.>, <(info)>, #<testExp> ), time }
STATIC s_lStdOut := .F.
#ifdef __HARBOUR__
#ifndef __XHARBOUR__
#include "hbver.ch"
#endif
#endif
#ifdef __HARBOUR__
proc main( ... )
local aParams := hb_aparams()
#else
proc main( _p01, _p02, _p03, _p04, _p05, _p06, _p07, _p08, _p09, _p10, ;
_p11, _p12, _p13, _p14, _p15, _p16, _p17, _p18, _p19, _p20 )
local aParams := ;
asize( { _p01, _p02, _p03, _p04, _p05, _p06, _p07, _p08, _p09, _p10, ;
_p11, _p12, _p13, _p14, _p15, _p16, _p17, _p18, _p19, _p20 }, ;
min( pCount(), 20 ) )
#endif
local nMT, cExclude, lScale, cParam, cMemTests, lSyntax, i, j
SET DATE ANSI
SET CENTURY ON
lSyntax := lScale := .f.
cMemTests := "030 031 023 025 027 041 042 044 053 054 019 022 032 033 055 056 "
cExclude := ""
nMT := 0
for j := 1 to len( aParams )
cParam := lower( aParams[ j ] )
if cParam = "--thread"
if substr( cParam, 9, 1 ) == "="
if isdigit( substr( cParam, 10, 1 ) )
nMT := val( substr( cParam, 10 ) )
elseif substr( cParam, 10 ) == "all"
nMT := -1
else
lSyntax = .t.
endif
elseif empty( substr( cParam, 9 ) )
nMT := -1
else
lSyntax = .t.
endif
elseif cParam = "--exclude="
if substr( cParam, 11 ) == "mem"
cExclude += cMemTests
else
cExclude += strtran( strtran( strtran( substr( cParam, 11 ), ;
".", " " ), ".", " " ), "/", " " ) + " "
endif
elseif cParam = "--only="
cExclude := ""
if substr( cParam, 8 ) == "mem"
cParam := cMemTests
endif
for i := 1 to N_TESTS
if !strzero( i, 3 ) $ cParam
cExclude += strzero( i, 3 ) + " "
endif
next
elseif cParam == "--scale"
lScale := .t.
elseif cParam == "--stdout"
s_lStdOut := .t.
else
lSyntax = .t.
endif
if lSyntax
? "Unknown option:", cParam
? "syntax: speedtst [--thread[=<num>]] [--only=<test(s)>] [--exclude=<test(s)>]"
?
return
endif
next
IF ! s_lStdOut
set alternate to ( spd_logfile() ) additive
set alternate on
ENDIF
// set console off
test( nMT, cExclude, lScale )
IF ! s_lStdOut
set alternate off
set alternate to
ENDIF
return
STATIC PROCEDURE spd_out( p1, p2, p3, p4, p5, p6 )
LOCAL nPCount := PCount()
IF s_lStdOut
DO CASE
CASE nPCount == 0 ; OutStd( EOL )
CASE nPCount == 1 ; OutStd( p1 )
CASE nPCount == 2 ; OutStd( p1, p2 )
CASE nPCount == 3 ; OutStd( p1, p2, p3 )
CASE nPCount == 4 ; OutStd( p1, p2, p3, p4 )
CASE nPCount == 5 ; OutStd( p1, p2, p3, p4, p5 )
CASE nPCount == 6 ; OutStd( p1, p2, p3, p4, p5, p6 )
ENDCASE
ELSE
DO CASE
CASE nPCount == 0 ; QOut()
CASE nPCount == 1 ; QQOut( p1 )
CASE nPCount == 2 ; QQOut( p1, p2 )
CASE nPCount == 3 ; QQOut( p1, p2, p3 )
CASE nPCount == 4 ; QQOut( p1, p2, p3, p4 )
CASE nPCount == 5 ; QQOut( p1, p2, p3, p4, p5 )
CASE nPCount == 6 ; QQOut( p1, p2, p3, p4, p5, p6 )
ENDCASE
ENDIF
RETURN
STATIC FUNCTION spd_logfile()
#ifndef __HARBOUR__
RETURN "speedtst.txt"
#else
LOCAL cName
hb_FNameSplit( hb_ArgV( 0 ),, @cName )
RETURN hb_FNameMerge( , cName, ".txt" )
#endif
/*** TESTS ***/
TEST t000 INFO "empty loop overhead" CODE
TEST t001 WITH L_C:=dtos(date()) CODE x := L_C
TEST t002 WITH L_N:=112345.67 CODE x := L_N
TEST t003 WITH L_D:=date() CODE x := L_D
TEST t004 STATIC s_once := NIL, S_C ;
INIT hb_threadOnce( @s_once, {|| S_C := dtos( date() ) } ) ;
CODE x := S_C
TEST t005 STATIC s_once := NIL, S_N ;
INIT hb_threadOnce( @s_once, {|| S_N := 112345.67 } ) ;
CODE x := S_N
TEST t006 STATIC s_once := NIL, S_D ;
INIT hb_threadOnce( @s_once, {|| S_D := date() } ) ;
CODE x := S_D
TEST t007 MEMVAR M_C ;
PRIVATE M_C := dtos( date() ) ;
CODE x := M->M_C
TEST t008 MEMVAR M_N ;
PRIVATE M_N := 112345.67 ;
CODE x := M->M_N
TEST t009 MEMVAR M_D ;
PRIVATE M_D := date() ;
CODE x := M->M_D
TEST t010 STATIC s_once := NIL ;
MEMVAR P_C ;
PUBLIC P_C ;
INIT hb_threadOnce( @s_once, {|| M->P_C := dtos( date() ) } ) ;
CODE x := M->P_C
TEST t011 STATIC s_once := NIL ;
MEMVAR P_N ;
PUBLIC P_N ;
INIT hb_threadOnce( @s_once, {|| M->P_N := 112345.67 } ) ;
CODE x := M->P_N
TEST t012 STATIC s_once := NIL ;
MEMVAR P_D ;
PUBLIC P_D ;
INIT hb_threadOnce( @s_once, {|| M->P_D := date() } ) ;
CODE x := M->P_D
TEST t013 FIELD F_C ;
INIT use_dbsh() EXIT close_db() ;
CODE x := F_C
TEST t014 FIELD F_N ;
INIT use_dbsh() EXIT close_db() ;
CODE x := F_N
TEST t015 FIELD F_D ;
INIT use_dbsh() EXIT close_db() ;
CODE x := F_D
TEST t016 WITH o := errorNew() CODE x := o:Args
TEST t017 WITH o := errorArray() CODE x := o[2]
TEST t018 CODE round( i / 1000, 2 )
TEST t019 CODE str( i / 1000 )
TEST t020 WITH s := stuff( dtos( date() ), 7, 0, "." ) CODE val( s )
TEST t021 WITH a := afill( array( ARR_LEN ), ;
stuff( dtos( date() ), 7, 0, "." ) ) ;
CODE val( a [ i % ARR_LEN + 1 ] )
TEST t022 WITH d := date() CODE dtos( d - i % 10000 )
TEST t023 CODE eval( { || i % ARR_LEN } )
TEST t024 WITH bc := { || i % ARR_LEN } ;
INFO eval( bc := { || i % ARR_LEN } ) ;
CODE eval( bc )
TEST t025 CODE eval( { |x| x % ARR_LEN }, i )
TEST t026 WITH bc := { |x| x % ARR_LEN } ;
INFO eval( bc := { |x| x % ARR_LEN }, i ) ;
CODE eval( bc, i )
TEST t027 CODE eval( { |x| f1( x ) }, i )
TEST t028 WITH bc := { |x| f1( x ) } ;
INFO eval( bc := { |x| f1( x ) }, i ) ;
CODE eval( bc, i )
TEST t029 WITH bc := mkBlock( "{ |x| f1( x ) }" ) ;
INFO eval( bc := &("{ |x| f1( x ) }"), i ) ;
CODE eval( bc, i )
TEST t030 CODE x := &( 'f1(' + str(i) + ')' )
TEST t031 WITH bc CODE bc := &( '{|x|f1(x)}' ), eval( bc, i )
TEST t032 CODE x := valtype( x ) + valtype( i )
TEST t033 WITH a := afill( array( ARR_LEN ), ;
stuff( dtos( date() ), 7, 0, "." ) ) ;
CODE x := strzero( i % 100, 2 ) $ a[ i % ARR_LEN + 1 ]
TEST t034 WITH a := array( ARR_LEN ), s := dtos( date() ) ;
INIT aeval( a, { |x,i| a[i] := left( s + s, i ), x } ) ;
CODE x := a[ i % ARR_LEN + 1 ] == s
TEST t035 WITH a := array( ARR_LEN ), s := dtos( date() ) ;
INIT aeval( a, { |x,i| a[i] := left( s + s, i ), x } ) ;
CODE x := a[ i % ARR_LEN + 1 ] = s
TEST t036 WITH a := array( ARR_LEN ), s := dtos( date() ) ;
INIT aeval( a, { |x,i| a[i] := left( s + s, i ), x } ) ;
CODE x := a[ i % ARR_LEN + 1 ] >= s
TEST t037 WITH a := array( ARR_LEN ), s := dtos( date() ) ;
INIT aeval( a, { |x,i| a[i] := left( s + s, i ), x } ) ;
CODE x := a[ i % ARR_LEN + 1 ] <= s
TEST t038 WITH a := array( ARR_LEN ), s := dtos( date() ) ;
INIT aeval( a, { |x,i| a[i] := left( s + s, i ), x } ) ;
CODE x := a[ i % ARR_LEN + 1 ] < s
TEST t039 WITH a := array( ARR_LEN ), s := dtos( date() ) ;
INIT aeval( a, { |x,i| a[i] := left( s + s, i ), x } ) ;
CODE x := a[ i % ARR_LEN + 1 ] > s
TEST t040 WITH a := array( ARR_LEN ) ;
INIT aeval( a, { |x,i| a[i] := i, x } ) ;
CODE ascan( a, i % ARR_LEN )
TEST t041 WITH a := array( ARR_LEN ) ;
INIT aeval( a, { |x,i| a[i] := i, x } ) ;
CODE ascan( a, { |x| x == i % ARR_LEN } )
TEST t042 WITH a := {}, a2 := { 1, 2, 3 }, bc := { |x| f1(x) }, ;
s := dtos( date() ), s2 := "static text" ;
CODE iif( i%1000==0, a:={}, ) , aadd(a,{i,1,.t.,s,s2,a2,bc})
TEST t043 WITH a := {} CODE x := a
TEST t044 CODE x := {}
TEST t045 CODE f0()
TEST t046 CODE f1( i )
TEST t047 WITH c := dtos( date() ) ;
INFO "f2( c[1...8] )" ;
CODE f2( c )
TEST t048 WITH c := repl( dtos( date() ), 5000 ) ;
INFO "f2( c[1...40000] )" ;
CODE f2( c )
TEST t049 WITH c := repl( dtos( date() ), 5000 ) ;
INFO "f2( @c[1...40000] )" ;
CODE f2( @c )
TEST t050 WITH c := repl( dtos( date() ),5000 ), c2 ;
INFO "f2( @c[1...40000] ), c2 := c" ;
CODE f2( @c ), c2 := c
TEST t051 WITH a := {}, a2 := { 1, 2, 3 }, bc := { |x| f1(x) }, ;
s := dtos( date() ), s2 := "static text", n := 1.23 ;
CODE f3( a, a2, s, i, s2, bc, i, n, x )
TEST t052 WITH a := { 1, 2, 3 } CODE f2( a )
TEST t053 CODE x := f4()
TEST t054 CODE x := f5()
TEST t055 CODE x := space(16)
TEST t056 WITH c := dtos( date() ) CODE f_prv( c )
/*** end of tests ***/
#ifdef __MT__
function thTest( mtxJobs, aResults )
local xJob := NIL
while .T.
hb_mutexSubscribe( mtxJobs,, @xJob )
if xJob == NIL
exit
endif
aResults[ xJob ] := &( "t" + strzero( xJob, 3 ) )()
enddo
return nil
function thTestScale( mtxJobs, mtxResults )
local xJob := NIL
while .T.
hb_mutexSubscribe( mtxJobs,, @xJob )
if xJob == NIL
exit
endif
hb_mutexNotify( mtxResults, &( "t" + strzero( xJob, 3 ) )() )
enddo
return nil
#endif
proc test( nMT, cExclude, lScale )
local nLoopOverHead, nTimes, nSeconds, cNum, aThreads, aResults, ;
mtxJobs, mtxResults, nTimeST, nTimeMT, nTimeTotST, nTimeTotMT, ;
cTest, x, i, j
create_db()
#ifdef __HARBOUR__
#include "hbmemory.ch"
if MEMORY( HB_MEM_USEDMAX ) != 0
? "Warning !!! Memory statistic enabled."
?
endif
if type( "__DBGENTRY()" ) == "UI"
? "Warning !!! HVM debugger enabled."
?
endif
#endif
//? "Startup loop to increase CPU clock..."
//x := seconds() + 5; while x > seconds(); enddo
#ifdef __MT__
if !hb_mtvm()
#else
if .t.
#endif
if lScale
? "scale test available only in MULTI THREAD mode"
?
return
endif
if nMT != 0
? "SINGLE THREAD mode, number of threads set to 0"
nMT := 0
endif
endif
? date(), time(), os()
? version() + iif( hb_mtvm(), " (MT)" + iif( nMT != 0, "+", "" ), "" ), ""
#ifdef __HARBOUR__
?? hb_compiler(), ""
#endif
?? spd_cpu()
if lScale .and. nMT < 1
nMT := 1
endif
? "THREADS:", iif( nMT < 0, "all->" + ltrim( str( N_TESTS ) ), ltrim( str( nMT ) ) )
? "N_LOOPS:", ltrim( str( N_LOOPS ) )
if !empty( cExclude )
? "excluded tests:", cExclude
endif
x :=t000()
nLoopOverHead := x[2]
if lScale
? space(56) + "1 th." + str(nMT,3) + " th. factor"
? replicate("=",76)
else
? dsp_result( x, 0 )
? replicate("=",68)
endif
nSeconds := seconds()
nTimes := hb_secondsCPU()
nTimeTotST := nTimeTotMT := 0
#ifdef __MT__
if lScale
aThreads := array( nMT )
mtxJobs := hb_mutexCreate()
mtxResults := hb_mutexCreate()
for i:=1 to nMT
aThreads[ i ] := hb_threadStart( "thTestScale", mtxJobs, mtxResults )
next
for i:=1 to N_TESTS
cTest := strzero( i, 3 )
if !cTest $ cExclude
/* linear execution */
nTimeST := seconds()
for j:=1 to nMT
hb_mutexNotify( mtxJobs, i )
hb_mutexSubscribe( mtxResults,, @x )
cTest := x[1]
next
nTimeST := seconds() - nTimeST
nTimeTotST += nTimeST
/* simultaneous execution */
nTimeMT := seconds()
for j:=1 to nMT
hb_mutexNotify( mtxJobs, i )
next
for j:=1 to nMT
hb_mutexSubscribe( mtxResults,, @x )
cTest := x[1]
next
nTimeMT := seconds() - nTimeMT
nTimeTotMT += nTimeMT
? dsp_scaleResult( cTest, nTimeST, nTimeMT, nMT, nLoopOverHead )
endif
next
for i:=1 to nMT
hb_mutexNotify( mtxJobs, NIL )
next
hb_threadWaitForAll( aThreads )
elseif nMT < 0
aThreads := array( N_TESTS )
for i:=1 to N_TESTS
cNum := strzero( i, 3 )
if !cNum $ cExclude
aThreads[ i ] := hb_threadStart( "t" + cNum )
endif
next
for i:=1 to N_TESTS
if aThreads[ i ] != NIL .and. hb_threadJoin( aThreads[ i ], @x )
? dsp_result( x, nLoopOverHead )
endif
next
elseif nMT > 0
aThreads := array( nMT )
aResults := array( N_TESTS )
mtxJobs := hb_mutexCreate()
for i:=1 to nMT
aThreads[ i ] := hb_threadStart( "thTest", mtxJobs, aResults )
next
for i:=1 to N_TESTS
if !strzero( i, 3 ) $ cExclude
hb_mutexNotify( mtxJobs, i )
endif
next
for i:=1 to nMT
hb_mutexNotify( mtxJobs, NIL )
next
hb_threadWaitForAll( aThreads )
for i:=1 to N_TESTS
if aResults[ i ] != NIL
? dsp_result( aResults[ i ], nLoopOverHead )
endif
next
mtxJobs := NIL
else
for i:=1 to N_TESTS
cNum := strzero( i, 3 )
if !cNum $ cExclude
? dsp_result( &( "t" + cNum )(), nLoopOverHead )
endif
next
endif
#else
for i:=1 to N_TESTS
cNum := strzero( i, 3 )
if !cNum $ cExclude
? dsp_result( &( "t" + cNum )(), nLoopOverHead )
endif
next
#endif
nTimes := hb_secondsCPU() - nTimes
nSeconds := seconds() - nSeconds
if lScale
? replicate("=",76)
? dsp_scaleResult( " TOTAL ", nTimeTotST, nTimeTotMT, nMT, 0 )
? replicate("=",76)
else
? replicate("=",68)
endif
? dsp_result( { "total application time:", nTimes }, 0)
? dsp_result( { "total real time:", nSeconds }, 0 )
?
remove_db()
return
function f0()
return nil
function f1(x)
return x
function f2(x)
return nil
function f3(a,b,c,d,e,f,g,h,i)
return nil
function f4()
return space(4000)
function f5()
return space(5)
function f_prv(x)
memvar PRV_C
private PRV_C := x
return nil
/*
function f_pub(x)
memvar PUB_C
public PUB_C := x
return nil
function f_stat(x)
static STAT_C
STAT_C := x
return nil
*/
static function mkBlock(x)
return &x
static function errorArray()
#ifdef __NO_OBJ_ARRAY__
return array(16)
#else
return errorNew()
#endif
static func dsp_result( aResult, nLoopOverHead )
return padr( "[ " + left( aResult[1], 56 ) + " ]", 60, "." ) + ;
strtran( str( max( aResult[2] - nLoopOverHead, 0 ), 8, 2 ), " ", "." )
static func dsp_scaleResult( cTest, nTimeST, nTimeMT, nMT, nLoopOverHead )
if .f.
nTimeST := max( 0, nTimeST - nMT * nLoopOverHead )
nTimeMT := max( 0, nTimeMT - nMT * nLoopOverHead )
endif
return padr( "[ " + left( cTest, 50 ) + " ]", 54, "_" ) + ;
str( nTimeST, 6, 2 ) + " " + str( nTimeMT, 6, 2 ) + " ->" + ;
str( nTimeST / nTimeMT, 6, 2 )
#define TMP_FILE "_tst_tmp.dbf"
static proc create_db()
remove_db()
dbcreate( TMP_FILE, { {"F_C", "C", 10, 0},;
{"F_N", "N", 10, 2},;
{"F_D", "D", 8, 0} } )
use TMP_FILE exclusive
dbappend()
field->F_C := dtos(date())
field->F_N := 112345.67
field->F_D := date()
dbclosearea()
return
static proc remove_db()
ferase( TMP_FILE )
return
static proc close_db()
dbclosearea()
return
static proc use_dbsh()
use TMP_FILE shared
return
#ifdef __HARBOUR__
#ifndef __XHARBOUR__
static function spd_cpu()
return hb_version( HB_VERSION_CPU )
#endif
#endif
#ifdef __CLIPPER__
static function spd_cpu()
return "x86"
#endif
#ifdef FlagShip
static function spd_cpu()
return "?"
#endif
#ifdef __CLIP__
static function spd_cpu()
return "?"
#endif
#ifdef __XPP__
static function spd_cpu()
return "x86"
#endif
#ifdef __XHARBOUR__
static function spd_cpu()
return "?"
#endif
#ifdef __CLIPPER__
static function hb_mtvm()
return .f. /* Clipper does not support MT */
#endif
#ifdef FlagShip
static function hb_mtvm()
return .f. /* FlagShip does not support MT */
#endif
#ifdef __CLIP__
static function hb_mtvm()
return .t. /* CLIP always uses VM with MT support */
#endif
#ifdef __XPP__
static function hb_mtvm()
return .t. /* xBase++ always uses VM with MT support */
#endif
#ifdef __XHARBOUR__
static function hb_mtvm()
return hb_multiThread() /* check for MT support in xHarbour VM */
#endif
#ifndef __MT__
/* trivial single thread version of once execution */
static function hb_threadOnce( xOnceControl, bAction )
local lFirstCall := .f.
if xOnceControl == NIL
if bAction != NIL
eval( bAction )
endif
xOnceControl := .t.
lFirstCall := .t.
endif
return lFirstCall
#else
/* Add support for MT functions for used compiler
*/
#ifdef __XHARBOUR__
static function hb_mutexSubscribe( mtx, nTimeOut, xSubscribed )
local lSubscribed
if valtype( nTimeOut ) == "N"
nTimeOut := round( nTimeOut * 1000, 0 )
xSubscribed := Subscribe( mtx, nTimeOut, @lSubscribed )
else
xSubscribed := Subscribe( mtx )
lSubscribed := .t.
endif
return lSubscribed
static function hb_mutexNotify( mtx, xValue )
Notify( mtx, xValue )
return nil
/* In xHarbour there is race condition in JoinThread() which fails if
* thread have ended before call to JoinThread() so we cannot use it.
* Exactly the same problem exists in GetThreadId().
* As workaround we will use mutexes as thread IDs and notify/subscribe
* mechanism to simulate thread join operation and passing thread return
* value.
*/
static function hb_threadStart( ... )
local thId
thId := hb_mutexCreate()
/* For some reasons codeblocks as thread startup entry are broken
* in xHarbour so we use intermediate function instead
*/
StartThread( @_thFuncFirst(), thId, hb_aParams() )
return thId
static function _thFuncFirst( thID, aParams )
Notify( thId, hb_execFromArray( aParams ) )
return nil
static function hb_threadJoin( thId, xResult )
xResult := Subscribe( thId )
return .t.
static function hb_threadWaitForAll()
WaitForThreads()
return nil
static function hb_threadOnce( xOnceControl, bAction )
static s_mutex
local lFirstCall := .f.
if s_mutex == NIL
s_mutex := hb_mutexCreate()
endif
if xOnceControl == NIL
hb_mutexLock( s_mutex )
if xOnceControl == NIL
if bAction != NIL
eval( bAction )
endif
xOnceControl := .t.
lFirstCall := .t.
endif
hb_mutexUnlock( s_mutex )
endif
return lFirstCall
init proc once_init()
/* set workareas local to thread */
set workarea private
/* initialize mutex in hb_threadOnce() */
hb_threadOnce()
/* initialize error object to reduce to chance for possible crash
* when two threads try to create new error class simultaneously.
* xHarbour does not have any protection against such situation
*/
errorNew()
return
#endif /* __XHARBOUR__ */
#ifdef __XPP__
#ifdef __HARBOUR__
/* for testing. Harbour also can use xBase++ API in this code */
#include "hbclass.ch"
#endif
INIT PROCEDURE once_init()
/* initialize sync object in hb_threadOnce() */
hb_threadOnce()
RETURN
CLASS Notifier
PROTECTED:
VAR aQueue
VAR oSignal
EXPORTED:
METHOD init
SYNC METHOD notify
SYNC METHOD subscribe
ENDCLASS
METHOD Notifier:init
::aQueue := {}
::oSignal := Signal():new()
RETURN self
METHOD Notifier:notify( xValue )
AAdd( ::aQueue, xValue )
::oSignal:signal()
RETURN self
METHOD Notifier:subscribe()
LOCAL xResult
WHILE Len( ::aQueue ) == 0
::oSignal:wait()
ENDDO
xResult := ::aQueue[ 1 ]
ADel( ::aQueue, 1 )
ASize( ::aQueue, Len( ::aQueue ) - 1 )
RETURN xResult
STATIC FUNCTION hb_mutexSubscribe( mtx, nTimeOut, xResult )
/* Ignore timeout - it's not used in this test */
xResult := mtx:subscribe()
RETURN .T.
STATIC FUNCTION hb_mutexNotify( mtx, xValue )
RETURN mtx:notify( xValue )
STATIC FUNCTION hb_mutexCreate()
RETURN Notifier():new()
CLASS Once
EXPORTED:
SYNC METHOD onceDo
ENDCLASS
METHOD Once:onceDo( xOnceControl, bAction )
LOCAL lFirstCall := .f.
IF xOnceControl == NIL
IF bAction != NIL
Eval( bAction )
ENDIF
xOnceControl := .t.
lFirstCall := .t.
ENDIF
RETURN lFirstCall
STATIC FUNCTION hb_threadOnce( xOnceControl, bAction )
STATIC s_oObject := NIL
IF s_oObject == NIL
s_oObject := Once():new()
ENDIF
RETURN s_oObject:onceDo( @xOnceControl, bAction )
STATIC FUNCTION hb_threadStart( cFunc, xPar1, xPar2, xPar3 )
LOCAL oThread
oThread := Thread():new()
oThread:start( cFunc, xPar1, xPar2, xPar3 )
RETURN oThread
STATIC FUNCTION hb_threadJoin( oThread, xResult )
oThread:synchronize( 0 )
xResult := oThread:result
RETURN .T.
STATIC FUNCTION hb_threadWaitForAll( aThreads )
ThreadWaitAll( aThreads )
RETURN NIL
#endif /* __XPP__ */
/*
static function hb_threadStart( cFunc, xPar1, xPar2, xPar3 )
return nil
static function hb_threadJoin( thId, xResult )
return nil
static function hb_mutexCreate()
return nil
static function hb_mutexSubscribe()
return nil
static function hb_mutexLock()
return nil
static function hb_mutexUnlock()
return nil
static function hb_mutexNotify()
return nil
static function hb_threadWaitForAll()
return nil
static function hb_mtvm()
return .f.
*/
#endif
#ifdef FlagShip
static function fs_seconds()
LOCAL_DOUBLE nret := 0
#Cinline
{
#include <sys/time.h>
struct timeval tv;
if( gettimeofday(&tv, NULL) == 0 )
nret = (double) tv.tv_sec + (double) (tv.tv_usec) / 1000000;
}
#endCinline
return nret
#ifndef FlagShip5
FUNCTION cursesinit()
return nil
#endif
#endif