1
0
Fork 0
libreoffice/testtools/source/performance/ubtest.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

1275 lines
40 KiB
C++

/* -*- 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: */