diff options
Diffstat (limited to 'framework/test/threadtest.cxx')
-rw-r--r-- | framework/test/threadtest.cxx | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/framework/test/threadtest.cxx b/framework/test/threadtest.cxx new file mode 100644 index 000000000000..1e70fb31b397 --- /dev/null +++ b/framework/test/threadtest.cxx @@ -0,0 +1,738 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ +#include <macros/generic.hxx> +#include <macros/debug.hxx> +#include <threadhelp/resetableguard.hxx> +#include <threadhelp/transactionguard.hxx> + +#ifndef __FRAMEWORK_THREADHELP_RWLOCKBASE_HXX_ +#include <threadhelp/rwlockbase.hxx> +#endif + +#ifndef __FRAMEWORK_THREADHELP_TRANSACTIONBASE_HXX_ +#include <threadhelp/transactionbase.hxx> +#endif +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// other includes +//_________________________________________________________________________________________________________________ +#include <rtl/random.h> +#include <vos/process.hxx> +#include <vos/thread.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/time.h> + +#ifndef _OSL_INTERLOCK_H_ +#include <osl/interlock.h> +#endif + +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/msgbox.hxx> +#include <stdio.h> + +//_________________________________________________________________________________________________________________ +// const +//_________________________________________________________________________________________________________________ + +#define LOGFILE "threadtest.log" +#define STATISTICS_FILE "threadtest_statistic.csv" + +//_________________________________________________________________________________________________________________ +// namespace +//_________________________________________________________________________________________________________________ + +using namespace ::rtl ; +using namespace ::osl ; +using namespace ::vos ; +using namespace ::framework ; + +//_________________________________________________________________________________________________________________ +// defines +//_________________________________________________________________________________________________________________ + +/*---------------- Use follow defines to enable/disable some special features of this little test program! -------*/ + +#define ENABLE_LOG +//#define ENABLE_THREADDELAY +#define ENABLE_REQUESTCOUNT + +/*----------------------------------------------------------------------------------------------------------------*/ + +#ifdef ENABLE_LOG + #define LOG_SETA_START( NA, NID ) \ + { \ + sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ + ResetableGuard aLogGuard( m_aLogMutex ); \ + OStringBuffer sLog(256); \ + sLog.append( (sal_Int32)nTimeStamp ); \ + sLog.append( ": Thread[ " ); \ + sLog.append( NID ); \ + sLog.append( " ] call setA( " ); \ + sLog.append( NA ); \ + sLog.append( " )\n" ); \ + WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ + } + + #define LOG_SETA_END( NA, EREASON, NID ) \ + { \ + sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ + ResetableGuard aLogGuard( m_aLogMutex ); \ + OStringBuffer sLog(256); \ + sLog.append( (sal_Int32)nTimeStamp ); \ + sLog.append( ": Thread[ " ); \ + sLog.append( NID ); \ + if( EREASON == E_NOREASON ) \ + sLog.append( " ] finish setA( " ); \ + else \ + sLog.append( " ] was refused at setA( "); \ + sLog.append( NA ); \ + sLog.append( " )\n" ); \ + WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ + } + + #define LOG_GETA_START( NID ) \ + { \ + sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ + ResetableGuard aLogGuard( m_aLogMutex ); \ + OStringBuffer sLog(256); \ + sLog.append( (sal_Int32)nTimeStamp ); \ + sLog.append( ": Thread[ " ); \ + sLog.append( NID ); \ + sLog.append( " ] call getA()\n" ); \ + WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ + } + + #define LOG_GETA_END( NRETURN, EREASON, NID ) \ + { \ + sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ + ResetableGuard aLogGuard( m_aLogMutex ); \ + OStringBuffer sLog(256); \ + sLog.append( (sal_Int32)nTimeStamp ); \ + sLog.append( ": Thread[ " ); \ + sLog.append( NID ); \ + if( EREASON == E_NOREASON ) \ + sLog.append( " ] finish getA() with " ); \ + else \ + sLog.append( " ] was refused at getA() with " ); \ + sLog.append( NRETURN ); \ + sLog.append( "\n" ); \ + WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ + } + + #define LOG_WORKA_START( NA, NID ) \ + { \ + sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ + ResetableGuard aLogGuard( m_aLogMutex ); \ + OStringBuffer sLog(256); \ + sLog.append( (sal_Int32)nTimeStamp ); \ + sLog.append( ": Thread[ " ); \ + sLog.append( NID ); \ + sLog.append( " ] call workA( " ); \ + sLog.append( NA ); \ + sLog.append( " )\n" ); \ + WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ + } + + #define LOG_WORKA_END( NRETURN, EREASON, NID ) \ + { \ + sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ + ResetableGuard aLogGuard( m_aLogMutex ); \ + OStringBuffer sLog(256); \ + sLog.append( (sal_Int32)nTimeStamp ); \ + sLog.append( ": Thread[ " ); \ + sLog.append( NID ); \ + if( EREASON == E_NOREASON ) \ + sLog.append( " ] finish workA() with " ); \ + else \ + sLog.append( " ] was refused at workA() with " ); \ + sLog.append( NRETURN ); \ + sLog.append( "\n" ); \ + WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ + } + + #define LOG_INITEXCEPTION( SMETHOD, NID ) \ + { \ + sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ + ResetableGuard aLogGuard( m_aLogMutex ); \ + OStringBuffer sLog(256); \ + sLog.append( (sal_Int32)nTimeStamp ); \ + sLog.append( ": Thread[ " ); \ + sLog.append( NID ); \ + sLog.append( " ] get EInitException from \"" ); \ + sLog.append( SMETHOD ); \ + sLog.append( "\"\n" ); \ + WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ + } + + #define LOG_CLOSEEXCEPTION( SMETHOD, NID ) \ + { \ + sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ + ResetableGuard aLogGuard( m_aLogMutex ); \ + OStringBuffer sLog(256); \ + sLog.append( (sal_Int32)nTimeStamp ); \ + sLog.append( ": Thread[ " ); \ + sLog.append( NID ); \ + sLog.append( " ] get ECloseException from \"" ); \ + sLog.append( SMETHOD ); \ + sLog.append( "\"\n" ); \ + WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ + } + + #define LOG_INIT( NA, NID ) \ + { \ + sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ + ResetableGuard aLogGuard( m_aLogMutex ); \ + OStringBuffer sLog(256); \ + sLog.append( (sal_Int32)nTimeStamp ); \ + sLog.append( ": Thread[ " ); \ + sLog.append( NID ); \ + sLog.append( " ] initialize me with " ); \ + sLog.append( NA ); \ + sLog.append( "\n" ); \ + WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ + } + + #define LOG_CLOSE( NID ) \ + { \ + sal_uInt32 nTimeStamp = osl_getGlobalTimer(); \ + ResetableGuard aLogGuard( m_aLogMutex ); \ + OStringBuffer sLog(256); \ + sLog.append( (sal_Int32)nTimeStamp ); \ + sLog.append( ": Thread[ " ); \ + sLog.append( NID ); \ + sLog.append( " ] close me\n" ); \ + WRITE_LOGFILE( LOGFILE, sLog.makeStringAndClear() ) \ + } +#else + #define LOG_SETA_START( NA, NID ) + #define LOG_SETA_END( NA, EREASON, NID ) + #define LOG_GETA_START( NID ) + #define LOG_GETA_END( NRETURN, EREASON, NID ) + #define LOG_WORKA_START( NA, NID ) + #define LOG_WORKA_END( NRETURN, EREASON, NID ) + #define LOG_INITEXCEPTION( SMETHOD, NID ) + #define LOG_CLOSEEXCEPTION( SMETHOD, NID ) + #define LOG_INIT( NA, NID ) + #define LOG_CLOSE( NID ) +#endif + +//_________________________________________________________________________________________________________________ +// declarations +//_________________________________________________________________________________________________________________ + +sal_uInt16 getRandomValue() +{ + // Get new random value for thread-sleep! + // See run() for further informations. + // Always calculate a new random number. + sal_uInt16 nValue; + rtlRandomPool aPool = rtl_random_createPool(); + rtl_random_getBytes ( aPool, &nValue, 2 ); + rtl_random_destroyPool ( aPool ); + return nValue; +} + +/*-************************************************************************************************************//** + @descr This class is used from different threads at the same time. + We start working after calling init() first(!) ... + and finish it by calling close(). It exist two methods for reading/writing an + internal variable "A". Another function workA() do both things at the same time. + All public methods log information in a file if DO_LOG is defined. + + @attention Our public base class FaiRWLockBase is a struct with a RWLock as member. + This member can be used by guards to safe access at internal variables + in interface methods. + Another baseclass is the TransactionBase. They support rejection of wrong calls at wrong time. + e.g. calls after closing object! +*//*-*************************************************************************************************************/ + +class ThreadSafeClass : private TransactionBase + , private FairRWLockBase +{ + public: + + ThreadSafeClass (); + ~ThreadSafeClass(); + + // This methods are used from differnt threads + // to test this class. + void init ( sal_Int32 nA , + sal_Int32 nThreadID ); + void close ( sal_Int32 nThreadID ); + void setA ( sal_Int32 nA , + sal_Int32 nThreadID ); + sal_Int32 getA ( sal_Int32 nThreadID ); + sal_Int32 workA ( sal_Int32 nA , + sal_Int32 nThreadID ); + + #ifdef ENABLE_REQUESTCOUNT + // This methods are used for statistics only! + sal_Int32 getReadCount () { return m_nReadCount; } + sal_Int32 getWriteCount() { return m_nWriteCount; } + #endif + + private: + + sal_Int32 m_nA ; /// test member fro reading/writing + + #ifdef ENABLE_LOG + ::osl::Mutex m_aLogMutex ; /// mutex to serialize writing log file! + #endif + + #ifdef ENABLE_REQUESTCOUNT + oslInterlockedCount m_nReadCount ; /// statistic variables to count read/write requests + oslInterlockedCount m_nWriteCount ; + #endif +}; + +//_________________________________________________________________________________________________________________ +ThreadSafeClass::ThreadSafeClass() + : TransactionBase ( ) + , FairRWLockBase ( ) + , m_nA ( 0 ) + #ifdef ENABLE_REQUESTCOUNT + , m_nReadCount ( 0 ) + , m_nWriteCount ( 0 ) + #endif +{ +} + +//_________________________________________________________________________________________________________________ +ThreadSafeClass::~ThreadSafeClass() +{ +} + +//_________________________________________________________________________________________________________________ +void ThreadSafeClass::init( sal_Int32 nA, sal_Int32 nThreadID ) +{ + // Set write lock for setting internal member AND + // protect changing of working mode! + WriteGuard aWriteLock( m_aLock ); + + LOG_INIT( nA, nThreadID ) + + // Look for multiple calls of this method first! + // Use E_SOFTEXCEPTIONS to disable automaticly throwing of exceptions for some working modes. + ERejectReason eReason; + TransactionGuard aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, eReason ); + if( eReason == E_UNINITIALIZED ) + { + // OK, it must be the first call and we are synchronized with all other threads by using the write lock! + // Otherwise (e.g. if working mode == E_WORK) we get a exception and follow lines are never called. + + // We can set our member and change the working mode now. + m_nA = nA; + m_aTransactionManager.setWorkingMode( E_WORK ); + } +} + +//_________________________________________________________________________________________________________________ +void ThreadSafeClass::close( sal_Int32 nThreadID ) +{ + // Make it threadsafe. + // It must be an exclusiv access! => WriteLock! + WriteGuard aWriteLock( m_aLock ); + + LOG_CLOSE( nThreadID ) + + // We must look for multiple calls of this method. + // Try to register this method as a transaction. + // In combination with E_HARDEXCEPTIONS only working mode E_WORK pass this barrier. + ERejectReason eReason; + TransactionGuard aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, eReason ); + if( eReason == E_NOREASON ) + { + // Change working mode to BEFORECLOSE to enable rejection of normal interface calls + // and enable SOFTEXCEPTION mode for some impl- or helper methods! + // Attention: We must stop successful registered transaction first ... + // because setWorkingMode() blocks and wait for all current existing ones! + aTransaction.stop(); + m_aTransactionManager.setWorkingMode( E_BEFORECLOSE ); + + // Now we are alone ... + // All further calls to this object are rejected ... + // (not all ... some special ones can work by using E_SOFTEXCEPTIONS!) + + // Deinitialize all member and set working mode to E_CLOSE. + m_nA = 0; + m_aTransactionManager.setWorkingMode( E_CLOSE ); + } +} + +//_________________________________________________________________________________________________________________ +void ThreadSafeClass::setA( sal_Int32 nA, sal_Int32 nThreadID ) +{ + // Make it threadsafe. + WriteGuard aWriteLock( m_aLock ); + + LOG_SETA_START( nA, nThreadID ) + + // Register this method as a transaction to prevent code against wrong calls + // after close() or before init()! + ERejectReason eReason; + TransactionGuard aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, eReason ); + if( eReason == E_NOREASON ) + { + // This object is ready for working and we have full write access. + // We can work with our member. + m_nA = nA; + #ifdef ENABLE_REQUESTCOUNT + osl_incrementInterlockedCount( &m_nWriteCount ); + #endif + } + LOG_SETA_END( nA, eReason, nThreadID ) +} + +//_________________________________________________________________________________________________________________ +sal_Int32 ThreadSafeClass::getA( sal_Int32 nThreadID ) +{ + // Make it threadsafe. + ReadGuard aReadLock( m_aLock ); + + LOG_GETA_START( nThreadID ) + + // Register this method as a transaction to prevent code against wrong calls + // after close() or before init()! + sal_Int32 nReturn = 0; + ERejectReason eReason; + TransactionGuard aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, eReason ); + if( eReason == E_NOREASON ) + { + // This object is ready for working and we have a read access. + // We can work with our member. + nReturn = m_nA; + #ifdef ENABLE_REQUESTCOUNT + osl_incrementInterlockedCount( &m_nReadCount ); + #endif + } + + LOG_GETA_END( nReturn, eReason, nThreadID ) + return nReturn; +} + +//_________________________________________________________________________________________________________________ +sal_Int32 ThreadSafeClass::workA( sal_Int32 nA , + sal_Int32 nThreadID ) +{ + // This method test the downgrade-mechanism of used lock implementation! + // Make it threadsafe. + WriteGuard aWriteLock( m_aLock ); + + LOG_WORKA_START( nA, nThreadID ) + + // Register this method as a transaction to prevent code against wrong calls + // after close() or before init()! + sal_Int32 nReturn = 0; + ERejectReason eReason; + TransactionGuard aTransaction( m_aTransactionManager, E_NOEXCEPTIONS, eReason ); + if( eReason == E_NOREASON ) + { + // We have write access to our member. + // Set new value. + m_nA = nA; + #ifdef ENABLE_REQUESTCOUNT + osl_incrementInterlockedCount( &m_nWriteCount ); + #endif + + // Downgrade write access to read access and read the set value again. + // This call can't be rejected - but it can fail! + aWriteLock.downgrade(); + nReturn = m_nA; + #ifdef ENABLE_REQUESTCOUNT + osl_incrementInterlockedCount( &m_nReadCount ); + #endif + } + + LOG_WORKA_END( nReturn, eReason, nThreadID ) + return nReturn; +} + +/*-****************************************************************************************************//** + @descr Every thread instance of these class lopp from 0 up to "nLoops". + He sleep for a random time and work with given test class "pClass" then. + We use random values for waiting for better results! + Otherwise all threads are sychron after first 2,3...5 calls - I think! +*//*-*****************************************************************************************************/ + +class TestThread : public OThread +{ + public: + + TestThread( ThreadSafeClass* pClass , + sal_Int32 nLoops , + Condition* pListener , + sal_Bool bOwner = sal_False ); + + private: + + virtual void SAL_CALL run (); + virtual void SAL_CALL onTerminated (); + + private: + + ThreadSafeClass* m_pClass ; + sal_Int32 m_nLoops ; + sal_Int32 m_nThreadID ; + Condition* m_pListener ; + sal_Bool m_bOwner ; +}; + +//_________________________________________________________________________________________________________________ +TestThread::TestThread( ThreadSafeClass* pClass , + sal_Int32 nLoops , + Condition* pListener , + sal_Bool bOwner ) + : m_pClass ( pClass ) + , m_nLoops ( nLoops ) + , m_pListener ( pListener ) + , m_bOwner ( bOwner ) +{ +} + +//_________________________________________________________________________________________________________________ +void SAL_CALL TestThread::run() +{ + // Get ID of this thread. + // Is used for logging information ... + m_nThreadID = getCurrentIdentifier(); + + // If we are the owner of given pClass + // we must initialize ... and close + // it. See at the end of this method too. + if( m_bOwner == sal_True ) + { + m_pClass->init( 0, m_nThreadID ); + } + + #ifdef ENABLE_THREADDELAY + TimeValue nDelay ; + #endif + + sal_Int32 nA ; + + for( sal_Int32 nCount=0; nCount<m_nLoops; ++nCount ) + { + // Work with class. + // Use random to select called method. + nA = (sal_Int32)getRandomValue(); + if( nA % 5 == 0 ) + { + nA = m_pClass->workA( nA, m_nThreadID ); + } + else + if( nA % 3 == 0 ) + { + m_pClass->setA( nA, m_nThreadID ); + } + else + { + nA = m_pClass->getA( m_nThreadID ); + } + #ifdef ENABLE_THREADDELAY + // Sleep - use random value to do that too! + nDelay.Seconds = 0; + nDelay.Nanosec = getRandomValue(); + sleep( nDelay ); + #endif + } + + // Don't forget to "close" teset object if you are the owner! + if( m_bOwner == sal_True ) + { + m_pClass->close( m_nThreadID ); + } +} + +//_________________________________________________________________________________________________________________ +void SAL_CALL TestThread::onTerminated() +{ + // Destroy yourself if you finished. + // But don't forget to call listener before. + m_pListener->set(); + + m_pClass = NULL; + m_pListener = NULL; + + delete this; +} + +/*-****************************************************************************************************//** + @descr This is our test application. + We create one ThreadSafeClass object and a lot of threads + which use it at different times. +*//*-*****************************************************************************************************/ + +struct ThreadInfo +{ + Condition* pCondition ; + TestThread* pThread ; +}; + +class TestApplication : public Application +{ + public: + void Main ( ); + sal_Int32 measureTime ( sal_Int32 nThreadCount , + sal_Int32 nOwner , + sal_Int32 nLoops=0 ); +}; + +//_________________________________________________________________________________________________________________ +// definition +//_________________________________________________________________________________________________________________ + +TestApplication aApplication; + +//_________________________________________________________________________________________________________________ +// This function start "nThreadCount" threads to use same test class. +// You can specify the owner thread of this test class which start/stop it by using "nOwner". [1..nThreadcount]! +// If you specify "nLoops" different from 0 we use it as loop count for every started thread. +// Otherwise we work with random values. +sal_Int32 TestApplication::measureTime( sal_Int32 nThreadCount , + sal_Int32 nOwner , + sal_Int32 nLoops ) +{ + // This is the class which should be tested. + ThreadSafeClass aClass; + + // Create list of threads. + ThreadInfo* pThreads = new ThreadInfo[nThreadCount]; + sal_Int32 nLoopCount = nLoops ; + sal_Bool bOwner = sal_False ; + for( sal_Int32 nI=1; nI<=nThreadCount; ++nI ) + { + // If nLoops==0 => we must use random value; otherwise we must use given count ... + if( nLoops == 0 ) + { + nLoopCount = getRandomValue(); + } + // Search owner of class. + bOwner = sal_False; + if( nOwner == nI ) + { + bOwner = sal_True; + } + // initialize condition. + pThreads[nI].pCondition = new Condition; + // Initialize thread. + pThreads[nI].pThread = new TestThread( &aClass, nLoopCount, pThreads[nI].pCondition, bOwner ); + } + + // Start clock to get information about used time. + sal_uInt32 nStartTime ; + sal_uInt32 nEndTime ; + + nStartTime = osl_getGlobalTimer(); + + // Start threads ... + for( nI=1; nI<=nThreadCount; ++nI ) + { + pThreads[nI].pThread->create(); + } + + // Wait for threads ... + for( nI=1; nI<=nThreadCount; ++nI ) + { + pThreads[nI].pCondition->wait(); + delete pThreads[nI].pCondition; + pThreads[nI].pCondition = NULL; + } + + delete[] pThreads; + pThreads = NULL; + + nEndTime = osl_getGlobalTimer(); + + // Calc used time and return it. [ms] + return( nEndTime-nStartTime ); +} + +//_________________________________________________________________________________________________________________ +void TestApplication::Main() +{ + sal_Int32 nTestCount = 0; /// count of calling "measureTime()" + sal_Int32 nThreadCount = 0; /// count of used threads by "measure..." + sal_Int32 nLoops = 0; /// loop count for every thread + sal_Int32 nOwner = 0; /// number of owner thread + + // Parse command line. + // Attention: All parameter are required and must exist! + // syntax: "threadtest.exe <testcount> <threadcount> <loops> <owner>" + OStartupInfo aInfo ; + OUString sArgument ; + sal_Int32 nArgument ; + sal_Int32 nCount = aInfo.getCommandArgCount(); + + LOG_ASSERT2( nCount!=4 ,"TestApplication::Main()" , "Wrong argument line detected!") + + for( nArgument=0; nArgument<nCount; ++nArgument ) + { + aInfo.getCommandArg( nArgument, sArgument ); + if( nArgument== 0 ) nTestCount =sArgument.toInt32(); + if( nArgument== 1 ) nThreadCount=sArgument.toInt32(); + if( nArgument== 2 ) nLoops =sArgument.toInt32(); + if( nArgument== 3 ) nOwner =sArgument.toInt32(); + } + + // Start test. + OStringBuffer sBuf(256); + sal_Int32 nTime=0; + sBuf.append( "Nr.\tTime\tThreadCount\tLoops\tOwner\n" ); + for( sal_Int32 nI=1; nI<=nTestCount; ++nI ) + { + nTime = measureTime( nThreadCount, nOwner, nLoops ); + sBuf.append( nI ); + sBuf.append( "\t" ); + sBuf.append( nTime ); + sBuf.append( "\t" ); + sBuf.append( nThreadCount ); + sBuf.append( "\t" ); + sBuf.append( nLoops ); + sBuf.append( "\t" ); + sBuf.append( nOwner ); + sBuf.append( "\n" ); + } + + WRITE_LOGFILE( STATISTICS_FILE, sBuf.makeStringAndClear() ); + LOG_ERROR( "TApplication::Main()", "Test finish successful!" ) +} |