diff options
Diffstat (limited to '')
-rw-r--r-- | testtools/source/performance/ubtest.cxx | 1275 |
1 files changed, 1275 insertions, 0 deletions
diff --git a/testtools/source/performance/ubtest.cxx b/testtools/source/performance/ubtest.cxx new file mode 100644 index 000000000..17601820c --- /dev/null +++ b/testtools/source/performance/ubtest.cxx @@ -0,0 +1,1275 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <stdio.h> +#include <math.h> +#include <string> +#include <map> +#include <unordered_map> + +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <osl/module.h> +#include <osl/process.h> +#include <osl/thread.hxx> +#include <osl/conditn.hxx> +#include <osl/time.h> + +#ifdef _WIN32 +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#else +#include <sys/times.h> +#include <unistd.h> +#endif + +#include <rtl/string.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> + +#include <uno/environment.hxx> +#include <uno/lbnames.h> +#include <uno/mapping.hxx> + +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XMain.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/loader/XImplementationLoader.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/bridge/XUnoUrlResolver.hpp> +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/test/performance/XPerformanceTest.hpp> + +#define NLOOP 200000000 + +using namespace osl; +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::loader; +using namespace com::sun::star::registry; +using namespace com::sun::star::bridge; +using namespace com::sun::star::container; +using namespace com::sun::star::test::performance; + + +#define SERVICENAME "com.sun.star.test.performance.PerformanceTest" +#define IMPLNAME "com.sun.star.comp.performance.PerformanceTest" + +namespace benchmark_test +{ + +static inline sal_uInt32 getSystemTicks() +{ +#ifdef _WIN32 + return (sal_uInt32)GetTickCount(); +#else // only UNX supported for now + static sal_uInt32 nImplTicksPerSecond = 0; + static double dImplTicksPerSecond; + static double dImplTicksULONGMAX; + + struct tms aTms; + sal_uInt32 nTicks = (sal_uInt32)times( &aTms ); + + if ( !nImplTicksPerSecond ) + { + nImplTicksPerSecond = sysconf(_SC_CLK_TCK); + dImplTicksPerSecond = nImplTicksPerSecond; + dImplTicksULONGMAX = (double)(sal_uInt32)ULONG_MAX; + } + + double fTicks = nTicks; + fTicks *= 1000; + fTicks /= dImplTicksPerSecond; + fTicks = fmod (fTicks, dImplTicksULONGMAX); + + return (sal_uInt32)fTicks; +#endif +} + + +static void out( const char * pText, FILE * stream = stderr, + sal_Int32 nStart = -1, char cFillchar = ' ' ) +{ + static sal_Int32 s_nPos = 0; + + char ar[2] = { cFillchar, 0 }; + while (s_nPos < nStart) + { + ::fprintf( stream, ar ); + ++s_nPos; + } + + ::fprintf( stream, pText ); + + for ( const char * p = pText; *p; ++p ) + { + if (*p == '\n') + s_nPos = 0; + else + ++s_nPos; + } +} + +static inline void out( const OUString & rText, FILE * stream = stderr, + sal_Int32 nStart = -1, char cFillchar = ' ' ) +{ + OString aText( OUStringToOString( rText, RTL_TEXTENCODING_ASCII_US ) ); + out( aText.getStr(), stream, nStart, cFillchar ); +} + +static inline void out( double fVal, FILE * stream = stderr, + sal_Int32 nStart = -1, char cFillchar = ' ' ) +{ + char ar[128]; + ::snprintf( ar, sizeof(ar), (fVal < 0.000001 ? "%g" : "%f"), fVal ); + out( ar, stream, nStart, cFillchar ); +} + +static inline void out( sal_Int64 nVal, FILE * stream = stderr, + sal_Int32 nStart = -1, char cFillchar = ' ' ) +{ + char ar[128]; + ::snprintf( ar, sizeof(ar), "%" SAL_PRIdINT64, nVal ); + out( ar, stream, nStart, cFillchar ); +} + + +Reference< XSingleServiceFactory > loadLibComponentFactory( + const OUString & rLibName, const OUString & rImplName, + const Reference< XMultiServiceFactory > & xSF, const Reference< XRegistryKey > & xKey ) +{ + Reference< XSingleServiceFactory > xRet; + + OUStringBuffer aLibNameBuf( 32 ); +#ifdef SAL_UNX + aLibNameBuf.append( "lib" ); + aLibNameBuf.append( rLibName ); + aLibNameBuf.append( ".so" ); +#else + aLibNameBuf.append( rLibName ); + aLibNameBuf.append( ".dll" ); +#endif + OUString aLibName( aLibNameBuf.makeStringAndClear() ); + oslModule lib = osl_loadModule( aLibName.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL ); + + if (lib) + { + void * pSym; + + // ========================= LATEST VERSION ========================= + OUString aGetEnvName( COMPONENT_GETENV ); + if (pSym = osl_getSymbol( lib, aGetEnvName.pData )) + { + uno_Environment * pCurrentEnv = 0; + uno_Environment * pEnv = 0; + const char * pEnvTypeName = 0; + (*((component_getImplementationEnvironmentFunc)pSym))( &pEnvTypeName, &pEnv ); + + sal_Bool bNeedsMapping = + (pEnv || 0 != rtl_str_compare( pEnvTypeName, CPPU_CURRENT_LANGUAGE_BINDING_NAME )); + + OUString aEnvTypeName( OUString::createFromAscii( pEnvTypeName ) ); + + if (bNeedsMapping) + { + if (! pEnv) + uno_getEnvironment( &pEnv, aEnvTypeName.pData, 0 ); + if (pEnv) + { + OUString aCppEnvTypeName( CPPU_CURRENT_LANGUAGE_BINDING_NAME ); + uno_getEnvironment( &pCurrentEnv, aCppEnvTypeName.pData, 0 ); + if (pCurrentEnv) + bNeedsMapping = (pEnv != pCurrentEnv); + } + } + + OUString aGetFactoryName( COMPONENT_GETFACTORY ); + if (pSym = osl_getSymbol( lib, aGetFactoryName.pData )) + { + OString aImplName( OUStringToOString( rImplName, RTL_TEXTENCODING_ASCII_US ) ); + + if (bNeedsMapping) + { + if (pEnv && pCurrentEnv) + { + Mapping aCurrent2Env( pCurrentEnv, pEnv ); + Mapping aEnv2Current( pEnv, pCurrentEnv ); + + if (aCurrent2Env.is() && aEnv2Current.is()) + { + void * pSMgr = aCurrent2Env.mapInterface( + xSF.get(), cppu::UnoType<XMultiServiceFactory>::get() ); + void * pKey = aCurrent2Env.mapInterface( + xKey.get(), cppu::UnoType<XRegistryKey>::get() ); + + void * pSSF = (*((component_getFactoryFunc)pSym))( + aImplName.getStr(), pSMgr, pKey ); + + if (pKey) + (*pEnv->pExtEnv->releaseInterface)( pEnv->pExtEnv, pKey ); + if (pSMgr) + (*pEnv->pExtEnv->releaseInterface)( pEnv->pExtEnv, pSMgr ); + + if (pSSF) + { + aEnv2Current.mapInterface( + reinterpret_cast< void ** >( &xRet ), + pSSF, cppu::UnoType<XSingleServiceFactory>::get() ); + (*pEnv->pExtEnv->releaseInterface)( pEnv->pExtEnv, pSSF ); + } + } + } + } + else + { + XSingleServiceFactory * pRet = (XSingleServiceFactory *) + (*((component_getFactoryFunc)pSym))( + aImplName.getStr(), xSF.get(), xKey.get() ); + if (pRet) + { + xRet = pRet; + pRet->release(); + } + } + } + + if (pEnv) + (*pEnv->release)( pEnv ); + if (pCurrentEnv) + (*pCurrentEnv->release)( pCurrentEnv ); + } + + // ========================= PREVIOUS VERSION ========================= + else + { + OUString aGetFactoryName( CREATE_COMPONENT_FACTORY_FUNCTION ); + if (pSym = osl_getSymbol( lib, aGetFactoryName.pData )) + { + OUString aCppEnvTypeName( CPPU_CURRENT_LANGUAGE_BINDING_NAME ); + OUString aUnoEnvTypeName( UNO_LB_UNO ); + Mapping aUno2Cpp( aUnoEnvTypeName, aCppEnvTypeName ); + Mapping aCpp2Uno( aCppEnvTypeName, aUnoEnvTypeName ); + OSL_ENSURE( aUno2Cpp.is() && aCpp2Uno.is(), "### cannot get uno mappings!" ); + + if (aUno2Cpp.is() && aCpp2Uno.is()) + { + uno_Interface * pUComponentFactory = 0; + + uno_Interface * pUSFactory = (uno_Interface *)aCpp2Uno.mapInterface( + xSF.get(), cppu::UnoType<XMultiServiceFactory>::get() ); + uno_Interface * pUKey = (uno_Interface *)aCpp2Uno.mapInterface( + xKey.get(), cppu::UnoType<XRegistryKey>::get() ); + + pUComponentFactory = (*((CreateComponentFactoryFunc)pSym))( + rImplName.getStr(), pUSFactory, pUKey ); + + if (pUKey) + (*pUKey->release)( pUKey ); + if (pUSFactory) + (*pUSFactory->release)( pUSFactory ); + + if (pUComponentFactory) + { + XSingleServiceFactory * pXFactory = + (XSingleServiceFactory *)aUno2Cpp.mapInterface( + pUComponentFactory, cppu::UnoType<XSingleServiceFactory>::get() ); + (*pUComponentFactory->release)( pUComponentFactory ); + + if (pXFactory) + { + xRet = pXFactory; + pXFactory->release(); + } + } + } + } + } + + if (! xRet.is()) + osl_unloadModule( lib ); + } + + return xRet; +} + +template< class T > +static void createInstance( Reference< T > & rxOut, + const Reference< XMultiServiceFactory > & xMgr, + const OUString & rServiceName ) + throw (RuntimeException) +{ + Reference< XInterface > x( xMgr->createInstance( rServiceName ), UNO_QUERY ); + + if (! x.is()) + { + static sal_Bool s_bSet = sal_False; + if (! s_bSet) + { + MutexGuard aGuard( Mutex::getGlobalMutex() ); + if (! s_bSet) + { + Reference< XSet > xSet( xMgr, UNO_QUERY ); + if (xSet.is()) + { + // acceptor + xSet->insert( makeAny( loadLibComponentFactory( + OUString("acceptor"), + OUString("com.sun.star.comp.stoc.Acceptor"), + xMgr, Reference< XRegistryKey >() ) ) ); + // connector + xSet->insert( makeAny( loadLibComponentFactory( + OUString("connector"), + OUString("com.sun.star.comp.stoc.Connector"), + xMgr, Reference< XRegistryKey >() ) ) ); + // iiop bridge + xSet->insert( makeAny( loadLibComponentFactory( + OUString("remotebridge"), + OUString("com.sun.star.bridge.Bridge.various"), + xMgr, Reference< XRegistryKey >() ) ) ); + // bridge factory + xSet->insert( makeAny( loadLibComponentFactory( + OUString("brdgfctr"), + OUString("com.sun.star.comp.stoc.BridgeFactory"), + xMgr, Reference< XRegistryKey >() ) ) ); + // uno url resolver + xSet->insert( makeAny( loadLibComponentFactory( + OUString("uuresolver"), + OUString("com.sun.star.comp.bridge.UnoUrlResolver"), + xMgr, Reference< XRegistryKey >() ) ) ); + // java loader +// xSet->insert( makeAny( loadLibComponentFactory( +// OUString("javaloader"), +// OUString("com.sun.star.comp.stoc.JavaComponentLoader"), +// xMgr, Reference< XRegistryKey >() ) ) ); + } + s_bSet = sal_True; + } + } + x = xMgr->createInstance( rServiceName ); + } + + if (! x.is()) + { + throw RuntimeException( "cannot get service instance \"" + rServiceName ); + } + + rxOut = Reference< T >::query( x ); + if (! rxOut.is()) + { + throw RuntimeException( "service instance \"" + rServiceName + + "\" does not support demanded interface \"" + cppu::UnoType<T>::get().getTypeName() ); + } +} + + +inline static Sequence< OUString > getSupportedServiceNames() +{ + return { SERVICENAME }; +} + + +class TestImpl : public WeakImplHelper< XServiceInfo, XMain > +{ + Reference< XMultiServiceFactory > _xSMgr; + + Reference< XInterface > _xDirect; + Reference< XInterface > getDirect() throw (Exception); + Reference< XInterface > resolveObject( const OUString & rUnoUrl ) throw (Exception); + +public: + explicit TestImpl( const Reference< XMultiServiceFactory > & xSMgr ); + virtual ~TestImpl(); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() throw (RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName ) throw (RuntimeException); + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw (RuntimeException); + + // XMain + virtual sal_Int32 SAL_CALL run( const Sequence< OUString > & rArgs ) throw (RuntimeException); +}; + + +TestImpl::TestImpl( const Reference< XMultiServiceFactory > & xSMgr ) + : _xSMgr( xSMgr ) +{ +} + +TestImpl::~TestImpl() +{ +} + + +static Reference< XInterface > SAL_CALL TestImpl_create( const Reference< XMultiServiceFactory > & xSMgr ) +{ + return Reference< XInterface >( *new TestImpl( xSMgr ) ); +} + +// XServiceInfo + +OUString TestImpl::getImplementationName() + throw (RuntimeException) +{ + return OUString( IMPLNAME ); +} + +sal_Bool TestImpl::supportsService( const OUString & rServiceName ) + throw (RuntimeException) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > TestImpl::getSupportedServiceNames() + throw (RuntimeException) +{ + return benchmark_test::getSupportedServiceNames(); +} + + +Reference< XInterface > TestImpl::getDirect() + throw (Exception) +{ + if (! _xDirect.is()) + { + MutexGuard aGuard( Mutex::getGlobalMutex() ); + if (! _xDirect.is()) + { + Reference< XSingleServiceFactory > xFac( loadLibComponentFactory( + OUString("perfobj"), + OUString("com.sun.star.comp.performance.PerformanceTestObject"), + _xSMgr, Reference< XRegistryKey >() ) ); + if (! xFac.is()) + throw RuntimeException("no test object available!" ); + _xDirect = xFac->createInstance(); + } + } + return _xDirect; +} + +Reference< XInterface > TestImpl::resolveObject( const OUString & rUnoUrl ) + throw (Exception) +{ + Reference< XUnoUrlResolver > xResolver; + createInstance( + xResolver, _xSMgr, + OUString("com.sun.star.bridge.UnoUrlResolver") ); + + Reference< XInterface > xResolvedObject( xResolver->resolve( rUnoUrl ) ); + + if (! xResolvedObject.is()) + { + throw RuntimeException( "cannot resolve object \"" + rUnoUrl + "\"!" ); + } + + return xResolvedObject; +} + + +class TimeEntry +{ + sal_Int64 nLoop; + sal_uInt32 nTicks; + +public: + TimeEntry() + {} + TimeEntry( sal_Int64 nLoop_, sal_uInt32 nTicks_ ) + : nLoop( nLoop_ ) + , nTicks( nTicks_ ) + {} + + inline double secPerCall() const + { return (((double)nTicks) / (nLoop * 1000)); } + + double ratio( const TimeEntry & rEntry ) const; +}; + +double TimeEntry::ratio( const TimeEntry & rEntry ) const +{ + double f = rEntry.nTicks * nLoop; + if (f == 0.0) + { + return 0.0; + } + else + { + return (((double)(nTicks * rEntry.nLoop)) / f); + } +} + + +typedef std::map< std::string, TimeEntry > t_TimeEntryMap; + + +struct TimingSheet +{ + t_TimeEntryMap _entries; + void insert( const char * pText, sal_Int64 nLoop, sal_uInt32 nTicks ); +}; + +void TimingSheet::insert( const char * pText, sal_Int64 nLoop, sal_uInt32 nTicks ) +{ + _entries[ pText ] = TimeEntry( nLoop, nTicks ); +} + +typedef std::unordered_map< std::string, TimingSheet > t_TimingSheetMap; + +static void benchmark( + TimingSheet & rSheet, const Reference< XInterface > & xInstance, sal_Int64 nLoop ) + throw (Exception) +{ + Reference< XPerformanceTest > xBench( xInstance, UNO_QUERY_THROW ); + + sal_Int64 i; + sal_uInt32 tStart, tEnd; + + const Type & rKnownType = cppu::UnoType<XPerformanceTest>::get(); + const Type & rUnKnownType = cppu::UnoType<XSet>::get(); + + ComplexTypes aDummyStruct; + + + // oneway calls + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->async(); + sal_uInt32 tEndSend = getSystemTicks(); + xBench->sync(); + tEnd = getSystemTicks(); + rSheet.insert( "1a: sending simple oneway calls (no params, no return)", nLoop, tEndSend - tStart ); + rSheet.insert( "1b: simple oneway calls (no params, no return)", nLoop, tEnd - tStart ); + // synchron calls + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->sync(); + xBench->sync(); + tEnd = getSystemTicks(); + rSheet.insert( "1c: simple synchron calls (no params no return)", nLoop+1, tEnd - tStart ); + + // acquire + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->acquire(); + tEnd = getSystemTicks(); + rSheet.insert( "2a: interface acquire() calls", nLoop, tEnd - tStart ); + // release + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->release(); + tEnd = getSystemTicks(); + rSheet.insert( "2b: interface release() calls", nLoop, tEnd - tStart ); + + // queryInterface() for known type + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->queryInterface( rKnownType ); + tEnd = getSystemTicks(); + rSheet.insert( "2c: interface query for implemented type", nLoop, tEnd - tStart ); + // queryInterface() for unknown type + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->queryInterface( rUnKnownType ); + tEnd = getSystemTicks(); + rSheet.insert( "2d: interface query for unknown type", nLoop, tEnd - tStart ); + + // create and forget objects + Reference< XPerformanceTest > xBench2( xBench ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench2 = xBench2->createObject(); + tEnd = getSystemTicks(); + rSheet.insert( "3a: create and release test objects", nLoop, tEnd - tStart ); + + // hold new objects + Sequence< Reference< XInterface > > aSeq( nLoop / 100 ); + Reference< XInterface > * pSeq = aSeq.getArray(); + xBench2 = xBench; + i = aSeq.getLength(); + tStart = getSystemTicks(); + while (i--) + pSeq[i] = xBench2 = xBench2->createObject(); + tEnd = getSystemTicks(); + rSheet.insert( "3b: create and hold test objects", nLoop, tEnd - tStart ); + + // structs + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->complexIn( aDummyStruct ); + tEnd = getSystemTicks(); + rSheet.insert( "4a: complexIn() calls (in struct; return struct)", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->complexInout( aDummyStruct ); + tEnd = getSystemTicks(); + rSheet.insert( "4b: complexInout() calls (inout struct; return struct)", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->complexOneway( aDummyStruct ); + tEnd = getSystemTicks(); + rSheet.insert( "4c: complexOneway() oneway calls (in struct)", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->complexNoreturn( aDummyStruct ); + tEnd = getSystemTicks(); + rSheet.insert( "4d: complexNoreturn() calls (in struct)", nLoop, tEnd - tStart ); + + // attributes, get() methods + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getLong(); + tEnd = getSystemTicks(); + rSheet.insert( "5a: getLong() call", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getLong_attr(); + tEnd = getSystemTicks(); + rSheet.insert( "5b: get long attribute", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setLong( 0 ); + tEnd = getSystemTicks(); + rSheet.insert( "5c: setLong() call", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setLong_attr( 0 ); + tEnd = getSystemTicks(); + rSheet.insert( "5d: set long attribute", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getHyper(); + tEnd = getSystemTicks(); + rSheet.insert( "5e: getHyper() call", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getHyper_attr(); + tEnd = getSystemTicks(); + rSheet.insert( "5f: get hyper attribute", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setHyper( 0 ); + tEnd = getSystemTicks(); + rSheet.insert( "5g: setHyper() call", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setHyper_attr( 0 ); + tEnd = getSystemTicks(); + rSheet.insert( "5h: set hyper attribute", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getFloat(); + tEnd = getSystemTicks(); + rSheet.insert( "5i: getFloat() call", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getFloat_attr(); + tEnd = getSystemTicks(); + rSheet.insert( "5j: get float attribute",nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setFloat( 0.0 ); + tEnd = getSystemTicks(); + rSheet.insert( "5k: setFloat() call", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setFloat_attr( 0.0 ); + tEnd = getSystemTicks(); + rSheet.insert( "5l: set float attribute", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getDouble(); + tEnd = getSystemTicks(); + rSheet.insert( "5m: getDouble() call", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getDouble_attr(); + tEnd = getSystemTicks(); + rSheet.insert( "5n: get double attribute", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setDouble( 0.0 ); + tEnd = getSystemTicks(); + rSheet.insert( "5o: setDouble() call", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setDouble_attr( 0.0 ); + tEnd = getSystemTicks(); + rSheet.insert( "5p: set double attribute", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getString(); + tEnd = getSystemTicks(); + rSheet.insert( "6a: getString() call (empty)", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getString_attr(); + tEnd = getSystemTicks(); + rSheet.insert( "6b: get empty string attribute", nLoop, tEnd - tStart ); + + i = nLoop; + OUString aDummyString; + tStart = getSystemTicks(); + while (i--) + xBench->setString( aDummyString ); + tEnd = getSystemTicks(); + rSheet.insert( "6c: setString() call (empty)", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setString_attr( aDummyString ); + tEnd = getSystemTicks(); + rSheet.insert( "6d: set empty string attribute", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getInterface(); + tEnd = getSystemTicks(); + rSheet.insert( "7a: getInterface() call (null)", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getInterface_attr(); + tEnd = getSystemTicks(); + rSheet.insert( "7b: get interface attribute", nLoop, tEnd - tStart ); + + i = nLoop; + Reference< XInterface > aDummyInterface; + tStart = getSystemTicks(); + while (i--) + xBench->setInterface( aDummyInterface ); + tEnd = getSystemTicks(); + rSheet.insert( "7c: setInterface() call (null)", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setInterface_attr( Reference< XInterface >() ); + tEnd = getSystemTicks(); + rSheet.insert( "7d: set interface attribute", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getAny(); + tEnd = getSystemTicks(); + rSheet.insert( "8a: getAny() call (empty)", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getAny_attr(); + tEnd = getSystemTicks(); + rSheet.insert( "8b: get empty any attribute", nLoop, tEnd - tStart ); + + i = nLoop; + Any aDummyAny; + tStart = getSystemTicks(); + while (i--) + xBench->setAny( aDummyAny ); + tEnd = getSystemTicks(); + rSheet.insert( "8c: setAny() call (empty)", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setAny_attr( aDummyAny ); + tEnd = getSystemTicks(); + rSheet.insert( "8d: set empty any attribute", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getSequence(); + tEnd = getSystemTicks(); + rSheet.insert( "9a: getSequence() call (empty)", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getSequence_attr(); + tEnd = getSystemTicks(); + rSheet.insert( "9b: get empty sequence attribute", nLoop, tEnd - tStart ); + i = nLoop; + Sequence< Reference< XInterface > > aDummySeq; + tStart = getSystemTicks(); + while (i--) + xBench->setSequence( aDummySeq ); + tEnd = getSystemTicks(); + rSheet.insert( "9c: setSequence() call (empty)", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setSequence_attr( aDummySeq ); + tEnd = getSystemTicks(); + rSheet.insert( "9d: set empty sequence attribute", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getStruct(); + tEnd = getSystemTicks(); + rSheet.insert( "Aa: getStruct() call", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->getStruct_attr(); + tEnd = getSystemTicks(); + rSheet.insert( "Ab: get struct attribute", nLoop, tEnd - tStart ); + + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setStruct( aDummyStruct ); + tEnd = getSystemTicks(); + rSheet.insert( "Ac: setStruct() call", nLoop, tEnd - tStart ); + i = nLoop; + tStart = getSystemTicks(); + while (i--) + xBench->setStruct_attr( aDummyStruct ); + tEnd = getSystemTicks(); + rSheet.insert( "Ad: set struct attribute", nLoop, tEnd - tStart ); + + // load +// i = nLoop; +// tStart = getSystemTicks(); +// while (i--) +// xBench->setSequence( aSeq ); +// tEnd = getSystemTicks(); +// rSheet.insert( "transfer of existing objects", nLoop, tEnd - tStart ); + + // exceptions + i = nLoop; + tStart = getSystemTicks(); + while (i--) + { + try + { + xBench->raiseRuntimeException(); + } + catch (RuntimeException &) + { + } + } + tEnd = getSystemTicks(); + rSheet.insert( "Ba: raising RuntimeException", nLoop, tEnd - tStart ); + + +} + + +static OUString extractParam( const Sequence< OUString > & rArgs, const OUString & rParam ) +{ + const OUString * pArgs = rArgs.getConstArray(); + for ( sal_Int32 nPos = rArgs.getLength(); nPos--; ) + { + if (pArgs[nPos].startsWith( rParam ) && + pArgs[nPos].getLength() > (rParam.getLength()+1)) + { + return pArgs[nPos].copy( rParam.getLength() +1 ); // XXX=bla + } + } + return OUString(); +} + +const sal_Int32 nMagicNumberDirect = 34000; + +//XMain + +sal_Int32 TestImpl::run( const Sequence< OUString > & rArgs ) + throw (RuntimeException) +{ + // defaults + FILE * stream = stderr; + sal_Int64 nLoop = NLOOP; + OUString aArg("dms"); + + try + { + OUString aLoopStr( extractParam( rArgs, OUString("loop") ) ); + if (aLoopStr.getLength()) + { + sal_Int64 n = aLoopStr.toInt64(); + if (n > 0) + nLoop = n; + } + + OUString aDurationStr( extractParam( rArgs , OUString("duration" ) ) ); + if( aDurationStr.getLength() ) + { + sal_Int64 n = aDurationStr.toInt64(); + if( n >0 ) + nLoop = nMagicNumberDirect * n; + } + + OUString aLogStr( extractParam( rArgs, OUString("log") ) ); + if (aLogStr.getLength()) + { + if (aLogStr.equalsAscii( "stderr" ) ) + { + stream = stderr; + } + else if (aLogStr.equalsAscii( "stdout" ) ) + { + stream = stdout; + } + else + { + OString aFileName( OUStringToOString( aLogStr, RTL_TEXTENCODING_ASCII_US ) ); + stream = ::fopen( aFileName.getStr(), "w" ); + if (! stream) + { + throw RuntimeException( "cannot open file for writing: \"" + aLogStr + "\"!" ); + } + } + } + + OUString aArgStr( extractParam( rArgs, OUString("opt") ) ); + if (aArgStr.getLength()) + { + aArg = aArgStr; + } + + if (! rArgs.getLength()) + out( "\n> no options given, using defaults" ); + + // params + out( "\n> opt=" ); + out( aArg ); + out( " log=" ); + if (stream == stderr) + out( "stderr" ); + else if (stream == stdout) + out( "stdout loop=" ); + else + out( aLogStr ); + out( " loop=" ); + out( nLoop ); + out( "\n" ); + t_TimingSheetMap aSheets; + TimingSheet aDirect; + + + if (aArg.indexOf( 'd' ) >= 0) + { + // in process direct test + sal_uInt32 nStart = getSystemTicks(); + benchmark( aDirect, getDirect(), nLoop ); + sal_uInt32 nEnd = getSystemTicks(); + fprintf( stderr, "Duration (direct in process): %g s\n", (nEnd - nStart)/1000. ); + } + + + if (aArg.indexOf( 'm' ) >= 0) + { + // in process uno dispatch + Environment aCppEnv, aAnoCppEnv; + OUString aCurrentLanguageBindingName( CPPU_CURRENT_LANGUAGE_BINDING_NAME ); + uno_getEnvironment( reinterpret_cast< uno_Environment ** >( &aCppEnv ), + aCurrentLanguageBindingName.pData, 0 ); + // anonymous + uno_createEnvironment( reinterpret_cast< uno_Environment ** >( &aAnoCppEnv ), + aCurrentLanguageBindingName.pData, 0 ); + + // pseudo mapping uno<->uno: does nothing! + Mapping aMapping( aCppEnv.get(), aAnoCppEnv.get(), OUString("pseudo") ); + if (! aMapping.is()) + throw RuntimeException("no pseudo mapping available!" ); + + Reference< XInterface > xMapped; + Reference< XInterface > xDirect( getDirect() ); + aMapping.mapInterface( reinterpret_cast< void ** >( &xMapped ), xDirect.get(), + cppu::UnoType<decltype(xDirect)>::get() ); + if (! xMapped.is()) + throw RuntimeException("mapping object failed!" ); + + sal_uInt32 nStart = getSystemTicks(); + benchmark( aSheets[ "mapped in process" ], xMapped, nLoop / 100 ); + sal_uInt32 nEnd = getSystemTicks(); + fprintf( stderr, "Duration (mapped in process): %g s\n", (nStart - nEnd)/1000. ); + } + + + if (aArg.indexOf( 's' ) >= 0) + { + // start server process + oslSecurity hSecurity = osl_getCurrentSecurity(); + if (! hSecurity) + throw RuntimeException("cannot get current security handle!" ); + + OUString aArgs[] = { + OUString("-c"), + OUString("com.sun.star.comp.performance.PerformanceTestObject"), + OUString("-l"), +#ifdef SAL_UNX + OUString("libperfobj.so"), +#else + OUString("perfobj.dll"), +#endif + OUString("-r"), + OUString("applicat.rdb"), + OUString("-u"), + OUString("uno:socket,host=localhost,port=6000;iiop;TestRemoteObject"), + OUString("--singleaccept") + }; + rtl_uString * pArgs[] = { + aArgs[0].pData, + aArgs[1].pData, + aArgs[2].pData, + aArgs[3].pData, + aArgs[4].pData, + aArgs[5].pData, + aArgs[6].pData, + aArgs[7].pData, + aArgs[8].pData, + }; + + out( "\n> executing: \"uno" ); + for ( sal_Int32 nPos = 0; nPos < (sizeof(aArgs) / sizeof(OUString)); ++nPos ) + { + out( " " ); + out( aArgs[nPos] ); + } + out( "\" ..." ); + + oslProcess hProcess = 0; + OUString aUnoExe("uno"); + OUString aWorkingDir("."); + osl_executeProcess( + aUnoExe.pData, pArgs, sizeof(aArgs) / sizeof(OUString), + osl_Process_SEARCHPATH | osl_Process_DETACHED | osl_Process_NORMAL, + hSecurity, aWorkingDir.pData, 0, 0, &hProcess ); + + osl_freeSecurityHandle( hSecurity ); + if (! hProcess) + throw RuntimeException("cannot start server process!" ); + osl_freeProcessHandle( hProcess ); + + // wait three seconds + osl::Thread::wait(std::chrono::seconds(3)); + + // connect and resolve outer process object + Reference< XInterface > xResolvedObject( resolveObject( OUString("uno:socket,host=localhost,port=6000;iiop;TestRemoteObject") ) ); + + benchmark( aSheets[ "remote same host" ], xResolvedObject, nLoop / 300 ); + } + + + if (aArg.indexOf( 'r' ) >= 0) + { + // remote + OUString aUnoUrl( extractParam( rArgs, OUString("url") ) ); + if (! aUnoUrl.getLength()) + throw RuntimeException( "performance test r(emote) needs additional uno url!" ); + + // connect and resolve outer process object + Reference< XInterface > xResolvedObject( resolveObject( aUnoUrl ) ); + + sal_Int32 t1 = getSystemTicks(); + OString o = OUStringToOString( aUnoUrl, RTL_TEXTENCODING_ASCII_US ); + benchmark( aSheets[ o.getStr() ], xResolvedObject, nLoop / 900 ); + sal_Int32 t2 = getSystemTicks(); + fprintf( stderr, "Duration (%s): %g s\n", o.getStr(),(t2 - t1)/1000. ); + } + + + if (aArg.indexOf( 'j' ) >= 0) + { + // java + benchmark( aSheets[ "java in process" ], + _xSMgr->createInstance("com.sun.star.comp.benchmark.JavaTestObject"), + nLoop / 1000 ); + } + + + // dump out tables + + out( "\nTimes( ratio to direct in process )", stream ); + out( ":", stream ); + + sal_Int32 nPos = 60; + out( "[direct in process]", stream, nPos ); + for ( const auto& rSheet : aSheets ) + { + nPos += 40; + out( "[", stream, nPos ); + out( rSheet.first.c_str(), stream ); + out( "]", stream ); + } + for ( const auto& rTopics : aDirect._entries ) + { + const std::string & rTopic = rTopics.first; + + out( "\n", stream ); + out( rTopic.c_str(), stream ); + + out( ":", stream, 58, '.' ); + + sal_Int32 nPos = 60; + + double secs = rTopics.second.secPerCall(); + if (secs > 0.0) + { + out( secs * 1000, stream, nPos ); + out( "ms", stream ); + } + else + { + out( "NA", stream, nPos ); + } + + for ( const auto& rSheet : aSheets ) + { + const t_TimeEntryMap::const_iterator iFind( rSheet.second._entries.find( rTopic ) ); + OSL_ENSURE( iFind != rSheet.second._entries.end(), "####" ); + + nPos += 40; + + double secs = (*iFind).second.secPerCall(); + if (secs != 0.0) + { + out( secs * 1000, stream, nPos ); + out( "ms", stream ); + + out( " (", stream ); + double ratio = (*iFind).second.ratio( rTopics.second ); + if (ratio != 0.0) + { + out( ratio, stream ); + out( " x)", stream ); + } + else + { + out( "NA)", stream ); + } + } + else + { + out( "NA", stream, nPos ); + } + } + } + } + catch (Exception & rExc) + { + if (stream != stderr && stream != stdout) + ::fclose( stream ); + throw RuntimeException( rExc.Message, rExc.Context ); + } + + if (stream != stderr && stream != stdout) + ::fclose( stream ); + + out( "\n> done.\n" ); + return 0; +} + +} + + +extern "C" +{ + +sal_Bool SAL_CALL component_writeInfo( + void * pServiceManager, void * pRegistryKey ) +{ + if (pRegistryKey) + { + try + { + Reference< XRegistryKey > xNewKey( + reinterpret_cast< XRegistryKey * >( pRegistryKey )->createKey( + OUString( "/" IMPLNAME "/UNO/SERVICES" ) ) ); + xNewKey->createKey( OUString( SERVICENAME ) ); + + return sal_True; + } + catch (InvalidRegistryException &) + { + OSL_FAIL( "### InvalidRegistryException!" ); + } + } + return sal_False; +} + +SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( + const char * pImplName, void * pServiceManager, void * pRegistryKey ) +{ + void * pRet = 0; + + if (pServiceManager && rtl_str_compare( pImplName, IMPLNAME ) == 0) + { + Reference< XSingleServiceFactory > xFactory( createSingleFactory( + reinterpret_cast< XMultiServiceFactory * >( pServiceManager ), + OUString( IMPLNAME ), + benchmark_test::TestImpl_create, + benchmark_test::getSupportedServiceNames() ) ); + + if (xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |