summaryrefslogtreecommitdiff
path: root/tests/test-performance
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-performance')
-rw-r--r--tests/test-performance/dbus-spammer/dbus-services.cpp120
-rw-r--r--tests/test-performance/dbus-spammer/dbus-services.h74
-rw-r--r--tests/test-performance/dbus-spammer/dbus-spammer.cpp238
-rw-r--r--tests/test-performance/dbus-spammer/dbus-spammer.pro21
-rw-r--r--tests/test-performance/template.html62
-rw-r--r--tests/test-performance/test-performance.pro15
-rw-r--r--tests/test-performance/test-resourceqt-performance-collector/ResultsUpload.cpp39
-rw-r--r--tests/test-performance/test-resourceqt-performance-collector/ResultsUpload.h26
-rw-r--r--tests/test-performance/test-resourceqt-performance-collector/test-resourceqt-performance-collector.cpp153
-rw-r--r--tests/test-performance/test-resourceqt-performance-collector/test-resourceqt-performance-collector.pro21
-rwxr-xr-xtests/test-performance/test-resourceqt-performance-runner.sh80
-rw-r--r--tests/test-performance/test-resourceqt-performance.ini12
-rw-r--r--tests/test-performance/test-resourceqt-performance/client.cpp380
-rw-r--r--tests/test-performance/test-resourceqt-performance/client.h175
-rw-r--r--tests/test-performance/test-resourceqt-performance/test-resourceqt-performance.cpp116
-rw-r--r--tests/test-performance/test-resourceqt-performance/test-resourceqt-performance.pro24
-rw-r--r--tests/test-performance/tests.xml37
17 files changed, 1593 insertions, 0 deletions
diff --git a/tests/test-performance/dbus-spammer/dbus-services.cpp b/tests/test-performance/dbus-spammer/dbus-services.cpp
new file mode 100644
index 0000000..d084ce0
--- /dev/null
+++ b/tests/test-performance/dbus-spammer/dbus-services.cpp
@@ -0,0 +1,120 @@
+#include "dbus-services.h"
+
+DbusSpammer::DbusSpammer(int id, QString service, int messageLen) : QThread()
+{
+ firstTime = true;
+// qDebug("Hello world from DbusSpammer::DbusSpammer(%d, %s, %d)", id, qPrintable(service), messageLen);
+
+ myBus = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+ if( myBus == NULL )
+ {
+ qDebug("Failed to access session bus!");
+ return;
+ }
+
+ threadID = id;
+ serviceName = service;
+ spamData.fill('A', messageLen);
+ pszSpamData = qPrintable(spamData);
+
+ myMessage = dbus_message_new_method_call(qPrintable(service), "/", NULL, "ping");
+ if( myMessage == NULL )
+ {
+ qDebug("Failed to create dbus message! Out of memory?");
+ return;
+ }
+
+ dbus_message_append_args(myMessage, DBUS_TYPE_STRING, &pszSpamData, DBUS_TYPE_INVALID);
+
+ timerID = startTimer(0);
+}
+
+DbusSpammer::~DbusSpammer()
+{
+ killTimer(timerID);
+
+ dbus_message_unref(myMessage);
+ dbus_connection_unref(myBus);
+}
+
+void DbusSpammer::run()
+{
+// sleep(1);
+// printf("Thread #%d: Using service '%s' ...\n", threadID, qPrintable(serviceName));
+
+ exec();
+}
+
+void DbusSpammer::timerEvent(QTimerEvent*)
+{
+ killTimer(timerID);
+
+ if( firstTime )
+ {
+ dbus_connection_send(myBus, myMessage, NULL);
+ dbus_connection_flush(myBus);
+ }
+ else
+ {
+ DBusError error;
+ dbus_error_init(&error);
+ DBusMessage* reply = dbus_connection_send_with_reply_and_block(myBus, myMessage, 1000, &error);
+
+ if( dbus_error_is_set(&error) )
+ {
+ if( QString(error.name) != QString("org.freedesktop.DBus.Error.AccessDenied") )
+ qDebug("Thread #%d dbus error %s:\n %s", threadID, error.name, error.message);
+ }
+
+ if( reply )
+ {
+ dbus_message_unref(reply);
+ }
+ }
+
+ firstTime = false;
+ timerID = startTimer(0);
+}
+
+DbusServer::DbusServer(int id)
+{
+ serviceID = id;
+ serviceName.sprintf("com.nokia.spam.dbus%d", id);
+}
+
+DbusServer::~DbusServer()
+{
+ if( myBus )
+ {
+ delete myBus;
+ myBus = NULL;
+ }
+}
+
+void DbusServer::run()
+{
+ myBus = new QDBusConnection(QDBusConnection::sessionBus().sessionBus());
+ if( !myBus || !myBus->isConnected() )
+ {
+ qDebug("Connection error!");
+ return;
+ }
+
+ if( !myBus->registerService(serviceName) )
+ {
+ qDebug("Service #%d: %s", serviceID, qPrintable(myBus->lastError().message()));
+ return;
+ }
+
+ // Register all slots as dbus methods
+ myBus->registerObject("/", this, QDBusConnection::ExportScriptableSlots);
+
+// qDebug("DbusServer(%d) running!", serviceID);
+ exec();
+}
+
+QString DbusServer::ping(const QString &arg)
+{
+ // Just return back
+ return QString("%1").arg(arg);
+}
diff --git a/tests/test-performance/dbus-spammer/dbus-services.h b/tests/test-performance/dbus-spammer/dbus-services.h
new file mode 100644
index 0000000..6924fdc
--- /dev/null
+++ b/tests/test-performance/dbus-spammer/dbus-services.h
@@ -0,0 +1,74 @@
+#ifndef _DBUS_THREAD_
+#define _DBUS_THREAD_
+
+#include <QList>
+#include <QtDBus/QtDBus>
+#include <QtCore/QObject>
+#include <QtCore/QCoreApplication>
+#include <dbus/dbus.h>
+
+typedef QList<QThread*> Threads;
+typedef QList<QObject*> Servers;
+
+class Maintainer : public QObject
+{
+ Q_OBJECT
+
+public:
+ Maintainer(Threads* t);
+ ~Maintainer();
+
+protected:
+ void timerEvent(QTimerEvent *e);
+
+ int timerID;
+ Threads* threads;
+ bool allOnline;
+};
+
+class DbusSpammer : public QThread
+{
+public:
+ DbusSpammer(int id, QString service, int messageLen);
+ ~DbusSpammer();
+
+ void run();
+
+ DBusConnection* myBus;
+ DBusMessage* myMessage;
+
+ bool firstTime;
+ bool exitThread;
+ int threadID;
+ const char* pszSpamData;
+ QString spamData;
+ QString serviceName;
+
+protected:
+ void timerEvent(QTimerEvent *e);
+
+ int timerID;
+};
+
+class DbusServer: public QThread
+{
+ Q_OBJECT
+
+public:
+ DbusServer(int id);
+ ~DbusServer();
+
+ const QString& getServiceName() { return serviceName; }
+ const int getServiceID() { return serviceID; }
+ void run();
+
+private:
+ QDBusConnection* myBus;
+ QString serviceName;
+ int serviceID;
+
+public slots:
+ Q_SCRIPTABLE QString ping(const QString &arg);
+};
+
+#endif // _DBUS_THREAD_
diff --git a/tests/test-performance/dbus-spammer/dbus-spammer.cpp b/tests/test-performance/dbus-spammer/dbus-spammer.cpp
new file mode 100644
index 0000000..2d84a60
--- /dev/null
+++ b/tests/test-performance/dbus-spammer/dbus-spammer.cpp
@@ -0,0 +1,238 @@
+#include <stdio.h>
+#include <signal.h>
+#include "dbus-services.h"
+
+sig_atomic_t volatile g_exit = 0;
+
+Maintainer::Maintainer(Threads* t) : QObject()
+{
+ allOnline = false;
+ threads = t;
+ timerID = startTimer(0);
+}
+
+Maintainer::~Maintainer()
+{
+ killTimer(timerID);
+}
+
+void Maintainer::timerEvent(QTimerEvent*)
+{
+ if( !allOnline )
+ {
+ int count = 0;
+ Threads::iterator th;
+ for( th = threads->begin(); th != threads->end(); ++th )
+ {
+ DbusSpammer* t = dynamic_cast<DbusSpammer*>(*th);
+ if( t )
+ {
+ if( t->firstTime )
+ count++;
+ }
+ }
+
+ allOnline = (count == 0) && (threads->count() > 0);
+
+ if( allOnline )
+ printf("All thread online and working!\n");
+ }
+
+ fflush(stdout);
+ fflush(stderr);
+
+ if( g_exit )
+ QMetaObject::invokeMethod(QCoreApplication::instance(), "quit");
+}
+
+class CommandLineParser
+{
+public:
+ CommandLineParser(int argc, char** argv)
+ {
+ threadCount = 10;
+ dataSize = 512;
+
+ parseArguments(argc, argv);
+ }
+
+public:
+ int threadCount;
+ int dataSize;
+
+private:
+ void parseArguments(int argc, char** argv)
+ {
+ int option, tmp;
+
+ while( (option = getopt(argc, argv, "ht:s:")) != -1 )
+ {
+ switch( option )
+ {
+ case 'h':
+ usage(0);
+ return;
+ case 't':
+ tmp = atoi(optarg);
+ if( tmp > 0 )
+ {
+ threadCount = tmp;
+ printf("Thread count: %d\n", threadCount);
+ }
+ else
+ {
+ printf("Invalid thread count, using default value %d!\n", threadCount);
+ }
+ break;
+ case 's':
+ tmp = atoi(optarg);
+ if( tmp > 0 )
+ {
+ dataSize = tmp;
+ printf("Data size: %d\n", dataSize);
+ }
+ else
+ {
+ printf("Invalid data size, using default value %d!\n", dataSize);
+ }
+ break;
+ default:
+ usage(-1);
+ return;
+ }
+ }
+ }
+
+ void usage(int theExitCode)
+ {
+ printf("usage: dbus-spammer [-h] [-t thread_count] [-s data_size]\n");
+ printf("default values:\n");
+ printf(" thread_count: %d\n", threadCount);
+ printf(" data_size : %d\n", dataSize);
+ exit(theExitCode);
+ }
+};
+
+void signal_handler(int signo, siginfo_t *info, void *data)
+{
+ switch( signo )
+ {
+ case SIGHUP:
+ case SIGTERM:
+ case SIGINT:
+ default:
+ puts("Caught exit signal!");
+ g_exit = 1;
+ }
+
+ (void)info;
+ (void)data;
+}
+
+bool installSignals()
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_sigaction = signal_handler;
+ sa.sa_flags = SA_SIGINFO;
+
+ if( sigaction(SIGHUP, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0 || sigaction(SIGINT, &sa, NULL) < 0 )
+ {
+ puts("Failed to install signal handlers");
+ return false;
+ }
+
+ return true;
+}
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ CommandLineParser cmd(argc, argv);
+
+ int count = cmd.threadCount;
+
+ Threads threads;
+ Servers servers;
+
+ if( !installSignals() )
+ {
+ return -2;
+ }
+
+ if( !QDBusConnection::sessionBus().isConnected() )
+ {
+ puts("Cannot connect to the D-Bus session bus.");
+ return -1;
+ }
+
+ Maintainer maintainer(&threads);
+
+ printf("Starting pair: ");
+ for( int i = 0; i < count; i++ )
+ {
+ printf("#%d", i);
+ fflush(stdout);
+ DbusServer* s = new DbusServer(i);
+ s->start(QThread::NormalPriority);
+ servers.push_back(s);
+ usleep(100000);
+
+ QThread* t = new DbusSpammer(i, s->getServiceName(), cmd.dataSize);
+ threads.push_back(t);
+ t->start(QThread::NormalPriority);
+ }
+
+ puts("");
+
+ app.exec();
+
+ Threads::iterator th;
+ printf("Cleaning thread: ");
+ for( th = threads.begin(); th != threads.end(); ++th )
+ {
+ DbusSpammer* t = dynamic_cast<DbusSpammer*>(*th);
+ if( t )
+ {
+ printf("#%d", t->threadID);
+
+ t->quit();
+ int cnt = 0;
+ while( t->isRunning() )
+ {
+ fflush(stdout);
+ fflush(stderr);
+ if( ++cnt == 1000 )
+ {
+ printf("[T!]");
+ t->terminate();
+ break;
+ }
+ usleep(1000);
+ }
+ delete t;
+ }
+ }
+ puts(" ... done!");
+
+ Servers::iterator sv;
+ printf("Cleaning service: ");
+ for( sv = servers.begin(); sv != servers.end(); ++sv )
+ {
+ DbusServer* s = dynamic_cast<DbusServer*>(*sv);
+ if( s )
+ {
+ printf("#%d", s->getServiceID());
+ s->quit();
+ while( !s->isFinished() )
+ usleep(1000);
+
+ delete s;
+ }
+ }
+
+ puts(" ... done!");
+
+ return 0;
+}
diff --git a/tests/test-performance/dbus-spammer/dbus-spammer.pro b/tests/test-performance/dbus-spammer/dbus-spammer.pro
new file mode 100644
index 0000000..752d740
--- /dev/null
+++ b/tests/test-performance/dbus-spammer/dbus-spammer.pro
@@ -0,0 +1,21 @@
+TEMPLATE = app
+TARGET = dbus-spammer
+MOC_DIR = .moc
+OBJECTS_DIR = .obj
+DEPENDPATH += .
+QT = core dbus
+CONFIG += console link_pkgconfig
+CONFIG -= app_bundle
+PKGCONFIG += dbus-1
+
+QMAKE_CXXFLAGS += -Wall
+
+# Input
+SOURCES += dbus-spammer.cpp dbus-services.cpp
+HEADERS += dbus-services.h
+
+QMAKE_DISTCLEAN += -r .moc .obj
+
+# Install options
+target.path = /usr/lib/libresourceqt-performance-tests/
+INSTALLS = target
diff --git a/tests/test-performance/template.html b/tests/test-performance/template.html
new file mode 100644
index 0000000..6134d68
--- /dev/null
+++ b/tests/test-performance/template.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/>
+<style type="text/css" href="default.css" media="screen">
+ body {
+ color: #555A60;
+ font: normal 62.5% "Lucida Sans Unicode",sans-serif;
+ margin: 0;
+ }
+ p,code,ul {
+ font-size: 1.2em;
+ padding-bottom: 1.2em;
+ }
+ h1 {
+ font-size: 1.4em;
+ margin-bottom: 4px;
+ }
+ th {
+ background-color: #AAAAAA;
+ color: #0;
+ }
+ code {
+ border: 2px solid #C6C6C6;
+ color: #666;
+ display: block;
+ font: normal 1.1em "Lucida Sans Unicode",serif;
+ margin-bottom: 12px;
+ padding: 8px 10px;
+ white-space: pre;
+ }
+ h1,h2,h3 {
+ color: #00AABB;
+ padding-top: 6px;
+ }
+
+ .main {
+ margin: 0 auto;
+ width: 730px;
+ }
+
+ /* holders */
+ .mybody {
+ padding: 0 32px;
+ }
+</style>
+
+<title>Performance testrun for libresourceqt</title>
+</head>
+
+<body>
+
+<div class="main">
+ <div class="mybody">
+%%TESTRUNINFO%%
+ </div>
+ More performance test results can be found at <a href="http://policy.research.nokia.com/performance/">http://policy.research.nokia.com/performance/</a>
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/tests/test-performance/test-performance.pro b/tests/test-performance/test-performance.pro
new file mode 100644
index 0000000..e4303e9
--- /dev/null
+++ b/tests/test-performance/test-performance.pro
@@ -0,0 +1,15 @@
+#####################################################################
+# Tests projectfile
+#####################################################################
+
+CONFIG += ordered
+TEMPLATE = subdirs
+
+SUBDIRS = dbus-spammer test-resourceqt-performance test-resourceqt-performance-collector
+
+# Install options
+testsxml.path = /usr/share/libresourceqt-performance-tests/
+testsxml.files = tests.xml
+testrunner.path = /usr/lib/libresourceqt-performance-tests/
+testrunner.files = test-resourceqt-performance-runner.sh test-resourceqt-performance.ini template.html
+INSTALLS = testsxml testrunner
diff --git a/tests/test-performance/test-resourceqt-performance-collector/ResultsUpload.cpp b/tests/test-performance/test-resourceqt-performance-collector/ResultsUpload.cpp
new file mode 100644
index 0000000..594b07f
--- /dev/null
+++ b/tests/test-performance/test-resourceqt-performance-collector/ResultsUpload.cpp
@@ -0,0 +1,39 @@
+/*
+ * ResultsUpload.cpp
+ *
+ * Created on: May 14, 2010
+ * Author: wlk
+ */
+
+#include "ResultsUpload.h"
+
+ResultsUpload::ResultsUpload(QString fileToUpload)
+{
+ networkManager = new QNetworkAccessManager(this);
+ uploadFile = new QFile(fileToUpload);
+ connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
+ uploadFile->open(QIODevice::ReadOnly);
+
+/* QNetworkAccessManager man;
+ QFile* f = new QFile("/usr/lib/libresourceqt-tests/test-performance.ini");
+ f->open(QIODevice::ReadOnly);
+ man.post(QNetworkRequest(QUrl("http://policy.research.nokia.com/performance/upload.php")), f);*/
+ networkManager->post(QNetworkRequest(QUrl("http://policy.research.nokia.com/performance/upload.php")), uploadFile);
+}
+
+ResultsUpload::~ResultsUpload()
+{
+ if( networkManager )
+ delete networkManager;
+
+ if( uploadFile )
+ {
+ uploadFile->close();
+ delete uploadFile;
+ }
+}
+
+void ResultsUpload::replyFinished(QNetworkReply* reply)
+{
+ QMetaObject::invokeMethod(QCoreApplication::instance(), "quit");
+}
diff --git a/tests/test-performance/test-resourceqt-performance-collector/ResultsUpload.h b/tests/test-performance/test-resourceqt-performance-collector/ResultsUpload.h
new file mode 100644
index 0000000..ebc6213
--- /dev/null
+++ b/tests/test-performance/test-resourceqt-performance-collector/ResultsUpload.h
@@ -0,0 +1,26 @@
+#ifndef _RESULTSUPLOAD_H_
+#define _RESULTSUPLOAD_H_
+
+#include <QObject>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QFile>
+
+class ResultsUpload : public QObject
+{
+ Q_OBJECT
+
+public:
+ ResultsUpload(QString fileToUpload);
+ virtual ~ResultsUpload();
+
+private slots:
+ void replyFinished(QNetworkReply* reply);
+
+private:
+ QNetworkAccessManager* networkManager;
+ QFile* uploadFile;
+};
+
+#endif // _RESULTSUPLOAD_H_
diff --git a/tests/test-performance/test-resourceqt-performance-collector/test-resourceqt-performance-collector.cpp b/tests/test-performance/test-resourceqt-performance-collector/test-resourceqt-performance-collector.cpp
new file mode 100644
index 0000000..a2aee81
--- /dev/null
+++ b/tests/test-performance/test-resourceqt-performance-collector/test-resourceqt-performance-collector.cpp
@@ -0,0 +1,153 @@
+#include <QtCore/QCoreApplication>
+#include <QtCore/QSettings>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QTextStream>
+#include "ResultsUpload.h"
+#include <stdlib.h>
+
+class Reporter
+{
+public:
+ Reporter(bool create)
+ {
+ QSettings settings("/usr/lib/libresourceqt-performance-tests/test-resourceqt-performance.ini", QSettings::IniFormat);
+
+ settings.beginGroup("main");
+ reportAcquire = settings.value("acqreport", "/tmp/acquire.csv").toString();
+ reportRelease = settings.value("relreport", "/tmp/release.csv").toString();
+ report = settings.value("report", "/tmp/resourceqt-performance.html").toString();
+ reportTemplate = settings.value("template", "/usr/lib/libresourceqt-tests/performance/template.html").toString();
+ timeLimit = settings.value("limit", 80.0).toDouble();
+ settings.endGroup();
+
+ if( create && QFile::exists(report) )
+ {
+ QFile::remove(report);
+ }
+
+ if( !QFile::exists(report) )
+ {
+ QFile::copy(reportTemplate, report);
+ }
+ }
+
+ void updateReport(bool finalize)
+ {
+ QFile f(report);
+ f.open(QIODevice::ReadOnly | QIODevice::Text);
+ QString data(f.readAll().data());
+ f.close();
+
+ QString replace, testName("name information missing"), testDesc("test information missing");
+ char* env = getenv("TEST_DESC");
+ if( env )
+ testDesc = env;
+
+ env = getenv("TEST_NAME");
+ if( env )
+ testName = env;
+
+ QString results;
+ QString resAcq, resRel, resHead;
+
+ readReport(reportAcquire, "Acquire", resAcq);
+ readReport(reportRelease, "Release", resRel);
+
+ resHead = "<tr><th>Type</th><th>Count</th><th>Limit [ms]</th><th>Average [ms]</th><th>Minimum [ms]</th><th>Maximum [ms]</th><th>Total time [ms]</th>\n";
+ results.sprintf("<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\">%s%s%s</table>", qPrintable(resHead), qPrintable(resAcq), qPrintable(resRel));
+ replace.sprintf("<h1>Testcase '%s'</h1>\n<p>%s</p>\n<h3>Test results</h3>\n%s\n<br /><br /><br />", qPrintable(testName), qPrintable(testDesc), qPrintable(results));
+ if( !finalize )
+ replace += "%%TESTRUNINFO%%";
+
+ data.replace("%%TESTRUNINFO%%", replace);
+
+ QFile::remove(report);
+ f.open(QIODevice::WriteOnly | QIODevice::Text);
+ QTextStream out(&f);
+ out << data;
+ f.close();
+ }
+
+public:
+ QString report;
+
+private:
+ QString reportAcquire;
+ QString reportRelease;
+ QString reportTemplate;
+ double timeLimit;
+
+ bool readReport(QString reportFile, QString name, QString& table)
+ {
+ QFile f(reportFile);
+
+ if( !f.open(QIODevice::ReadOnly | QIODevice::Text) )
+ {
+ table.sprintf("<tr><td>%s</td><td>N/A</td><td>%.2f</td><td bgcolor=\"#FF0000\">N/A</td><td>N/A</td><td>N/A</td><td>N/A</td>\n", qPrintable(name), timeLimit);
+ return false;
+ }
+
+ int tCount = 0;
+ double tMin = 0, tMax = 0, tAvg = 0, tTotal = 0;
+
+ for( int i = 0; i < 5; i++ )
+ {
+ char temp[1024];
+ if( f.readLine(temp, 1024) )
+ {
+ QString qtemp(temp);
+ QStringList l = qtemp.split(';');
+ QString name = l[0];
+ QString val = l[1];
+
+ if( name == "Cnt" )
+ tCount = val.toInt();
+ else if( name == "Tot")
+ tTotal = val.toDouble();
+ else if( name == "Max" )
+ tMax = val.toDouble();
+ else if( name == "Min" )
+ tMin = val.toDouble();
+ else if( name == "Avg" )
+ tAvg = val.toDouble();
+ }
+ }
+
+ QString color = "#00FF00";
+ if( tAvg > timeLimit )
+ color = "#FF0000";
+
+ table.sprintf("<tr><td>%s</td><td>%d</td><td>%.2f</td><td bgcolor=\"%s\">%.2f</td><td>%.2f</td><td>%.2f</td><td>%.2f</td>\n", qPrintable(name), tCount, timeLimit, qPrintable(color), tAvg, tMin, tMax, tTotal);
+ f.close();
+
+ return true;
+ }
+};
+
+int main(int argc, char** argv)
+{
+ bool createReport = false, finalizeReport = false;
+
+ if( argc > 1 )
+ {
+ QString param;
+ param = argv[1];
+ if( param == "--create" )
+ createReport = true;
+ else if( param == "--finalize" )
+ finalizeReport = true;
+ }
+
+ Reporter r(createReport);
+ r.updateReport(finalizeReport);
+
+ if( finalizeReport )
+ {
+ QCoreApplication app(argc, argv);
+ ResultsUpload u(r.report);
+ app.exec();
+ }
+
+ return 0;
+}
diff --git a/tests/test-performance/test-resourceqt-performance-collector/test-resourceqt-performance-collector.pro b/tests/test-performance/test-resourceqt-performance-collector/test-resourceqt-performance-collector.pro
new file mode 100644
index 0000000..2cffc92
--- /dev/null
+++ b/tests/test-performance/test-resourceqt-performance-collector/test-resourceqt-performance-collector.pro
@@ -0,0 +1,21 @@
+TEMPLATE = app
+TARGET = test-resourceqt-performance-collector
+MOC_DIR = .moc
+OBJECTS_DIR = .obj
+DEPENDPATH += .
+QT = core network
+CONFIG += console
+CONFIG -= app_bundle
+
+INCLUDEPATH += $${LIBRESOURCEINC}
+QMAKE_CXXFLAGS += -Wall
+
+# Input
+HEADERS = ResultsUpload.h
+SOURCES += test-resourceqt-performance-collector.cpp ResultsUpload.cpp
+
+QMAKE_DISTCLEAN += -r .moc .obj
+
+# Install options
+target.path = /usr/lib/libresourceqt-performance-tests/
+INSTALLS = target
diff --git a/tests/test-performance/test-resourceqt-performance-runner.sh b/tests/test-performance/test-resourceqt-performance-runner.sh
new file mode 100755
index 0000000..b255a9c
--- /dev/null
+++ b/tests/test-performance/test-resourceqt-performance-runner.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+# Source and export D-Bus session info
+. /tmp/session_bus_address.user
+
+# D-Bus spamming is default option
+nospam="0"
+spamparam="-t10 -s50"
+
+if [ $# -eq 0 ]
+then
+ echo "Usage: test-resourceqt-performance-runner.sh test_case_nr"
+ exit 2
+fi
+
+case "$1" in
+ 0)
+ export TEST_DESC="Testcase without dbus spamming"
+ export TEST_NAME="no dbus load"
+ nospam="1"
+ collectparam="--create"
+ ;;
+ 1)
+ export TEST_DESC="Testcase with 5 dbus spamming threads, message size 50 bytes"
+ export TEST_NAME="small dbus load"
+ spamparam="-t5 -s50"
+ ;;
+ 2)
+ export TEST_DESC="Testcase with 10 dbus spamming threads, message size 50 bytes"
+ export TEST_NAME="medium dbus load"
+ spamparam="-t10 -s50"
+ ;;
+ 3)
+ export TEST_DESC="Testcase with 20 dbus spamming threads, message size 50 bytes"
+ export TEST_NAME="heavy dbus load"
+ spamparam="-t20 -s50"
+ ;;
+ 4)
+ export TEST_DESC="Testcase with 20 dbus spamming threads, message size 150 bytes"
+ export TEST_NAME="very heavy dbus load"
+ spamparam="-t20 -s150"
+ collectparam="--finalize"
+ ;;
+ *)
+ echo "Usage: test-resourceqt-performance-runner.sh test_case_nr"
+ exit 2
+ ;;
+esac
+
+# Run spam server
+if [ "$nospam" != "1" ]
+then
+ /usr/lib/libresourceqt-performance-tests/dbus-spammer $spamparam &
+ if [ $? -ne 0 ]
+ then
+ exit 3;
+ fi
+ sleep 5
+fi
+
+# Check the speed!
+/usr/lib/libresourceqt-performance-tests/test-resourceqt-performance
+status=$?
+
+# Kill spammer
+if [ "$nospam" != "1" ]
+then
+ killall dbus-spammer
+fi
+
+# Collect the results
+/usr/lib/libresourceqt-performance-tests/test-resourceqt-performance-collector $collectparam
+
+if [ "$status" -ne 0 ]
+then
+ echo "Test failed with value $status"
+fi
+
+# Return number of failed acquire/release cycles, nothing should be failing...
+exit $status
diff --git a/tests/test-performance/test-resourceqt-performance.ini b/tests/test-performance/test-resourceqt-performance.ini
new file mode 100644
index 0000000..5039182
--- /dev/null
+++ b/tests/test-performance/test-resourceqt-performance.ini
@@ -0,0 +1,12 @@
+[main]
+acqreport=/tmp/acquire.csv
+relreport=/tmp/release.csv
+report=/tmp/resourceqt-performance.html
+template=/usr/lib/libresourceqt-performance-tests/template.html
+limit=80.0
+
+[config]
+AllResources="AudioPlayback,VideoPlayback"
+OptionalResources=
+ApplicationClass=player
+TestCount=100
diff --git a/tests/test-performance/test-resourceqt-performance/client.cpp b/tests/test-performance/test-resourceqt-performance/client.cpp
new file mode 100644
index 0000000..e172d21
--- /dev/null
+++ b/tests/test-performance/test-resourceqt-performance/client.cpp
@@ -0,0 +1,380 @@
+#include <QtCore/QCoreApplication>
+#include <QtCore/QFile>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/select.h>
+
+#include "client.h"
+
+using namespace ResourcePolicy;
+
+Client::Client(int testCnt, QString appClass, uint32_t all, uint32_t optional) : QObject()
+{
+ QSettings settings("/usr/lib/libresourceqt-performance-tests/test-resourceqt-performance.ini", QSettings::IniFormat);
+
+ settings.beginGroup("main");
+ reportAcquire = settings.value("acqreport", "/tmp/acquire.csv").toString();
+ reportRelease = settings.value("relreport", "/tmp/release.csv").toString();
+ settings.endGroup();
+
+ totalTestCount = testCnt;
+ applicationClass = appClass;
+ resourceSet = NULL;
+ testState = TestStart;
+ testCounter = 1;
+
+ allResources = all;
+ optionalResources = optional;
+ firstTime = true;
+
+ failed = 0;
+
+ mainTimerID = startTimer(0);
+}
+
+Client::~Client()
+{
+ killTimer(mainTimerID);
+
+ if( resourceSet != NULL )
+ {
+ delete resourceSet;
+ resourceSet = NULL;
+ }
+}
+
+uint32_t Client::parseResourceList(QString resourceListStr)
+{
+ struct
+ {
+ uint32_t resourceType;
+ const char* resourceName;
+ }
+ resourceDef[] =
+ {
+ { RES_AUDIO_PLAYBACK, "AudioPlayback" },
+ { RES_VIDEO_PLAYBACK, "VideoPlayback" },
+ { RES_AUDIO_RECORDING, "AudioRecording" },
+ { RES_VIDEO_RECORDING, "VideoRecording" },
+ { RES_VIBRA, "Vibra" },
+ { RES_LEDS, "Leds" },
+ { RES_BACKLIGHT, "BackLight" },
+ { RES_SYSTEM_BUTTON, "SystemButton" },
+ { RES_LOCK_BUTTON, "LockButton" },
+ { RES_SCALE_BUTTON, "ScaleButton" },
+ { RES_SNAP_BUTTON, "SnapButton" },
+ { RES_LENS_COVER, "LensCover" },
+ { 0, NULL }
+ };
+
+ uint32_t resourceList = 0;
+
+ if( resourceListStr.isEmpty() || resourceListStr.isNull() )
+ {
+ return 0;
+ }
+ else
+ {
+ QStringList resList = resourceListStr.split(",", QString::SkipEmptyParts);
+
+ for( int i = 0; i < resList.count(); i++ )
+ {
+ int pos = 0;
+ while( resourceDef[pos].resourceName != NULL )
+ {
+ if( resList[i] == resourceDef[pos].resourceName )
+ break;
+
+ pos++;
+ }
+
+ if( !resourceDef[pos].resourceName )
+ {
+ const char* res = qPrintable(resList[i]);
+ printf("Ignoring invalid resource name '%s'\n", res);
+ }
+ else
+ {
+ resourceList |= resourceDef[pos].resourceType;
+ }
+ }
+ }
+
+ return resourceList;
+}
+
+void Client::createSet(uint32_t list, uint32_t optional)
+{
+ uint32_t resources[] =
+ {
+ RES_AUDIO_PLAYBACK, RES_VIDEO_PLAYBACK, RES_AUDIO_RECORDING, RES_VIDEO_RECORDING, RES_VIBRA, RES_LEDS, RES_BACKLIGHT, RES_SYSTEM_BUTTON,
+ RES_LOCK_BUTTON, RES_SCALE_BUTTON, RES_SNAP_BUTTON, RES_LENS_COVER, 0
+ };
+
+ int pos = 0;
+ while( resources[pos] )
+ {
+ if( list & resources[pos] )
+ {
+ Resource* resource = NULL;
+ ResourceType res = getResourceType(resources[pos]);
+ bool opt = (optional & resources[pos]) == resources[pos];
+
+ resource = allocateResource(res, opt);
+ if( resource )
+ {
+ resourceSet->addResourceObject(resource);
+ }
+ }
+
+ pos++;
+ }
+}
+
+bool Client::initialize()
+{
+ if( resourceSet )
+ {
+ return false;
+ }
+
+ resourceSet = new ResourceSet(applicationClass);
+ if( resourceSet == NULL )
+ {
+ return false;
+ }
+ resourceSet->setAlwaysReply();
+
+ createSet(allResources, optionalResources);
+
+ if( !connect(resourceSet, SIGNAL(resourcesGranted(QList<ResourcePolicy::ResourceType> )), this, SLOT(resourceAcquiredHandler(QList<ResourcePolicy::ResourceType>))) )
+ {
+ return false;
+ }
+
+ if( !connect(resourceSet, SIGNAL(resourcesDenied()), this, SLOT(resourceDeniedHandler())) )
+ {
+ return false;
+ }
+
+ if( !connect(resourceSet, SIGNAL(lostResources()), this, SLOT(resourceLostHandler())) )
+ {
+ return false;
+ }
+
+ connect(resourceSet, SIGNAL(resourcesReleased()), this, SLOT(resourceReleasedHandler()));
+
+ return true;
+}
+
+bool Client::cleanup()
+{
+ if( !disconnect(resourceSet, SIGNAL(resourcesGranted(QList<ResourcePolicy::ResourceType> )), this, SLOT(resourceAcquiredHandler(QList<ResourcePolicy::ResourceType>))) )
+ {
+ return false;
+ }
+
+ if( !disconnect(resourceSet, SIGNAL(resourcesDenied()), this, SLOT(resourceDeniedHandler())) )
+ {
+ return false;
+ }
+
+ if( !disconnect(resourceSet, SIGNAL(lostResources()), this, SLOT(resourceLostHandler())) )
+ {
+ return false;
+ }
+
+ disconnect(resourceSet, SIGNAL(resourcesReleased()), this, SLOT(resourceReleasedHandler()));
+
+ if( resourceSet != NULL )
+ {
+ delete resourceSet;
+ resourceSet = NULL;
+ }
+
+ return true;
+}
+
+Resource* Client::allocateResource(ResourceType resource, bool optional)
+{
+ Resource* retValue = NULL;
+
+ switch( resource )
+ {
+ case AudioPlaybackType:
+ retValue = new AudioResource();
+ break;
+ case VideoPlaybackType:
+ retValue = new VideoResource();
+ break;
+ case AudioRecorderType:
+ retValue = new AudioRecorderResource();
+ break;
+ case VideoRecorderType:
+ retValue = new VideoRecorderResource();
+ break;
+ case VibraType:
+ retValue = new VibraResource();
+ break;
+ case LedsType:
+ retValue = new LedsResource();
+ break;
+ case BacklightType:
+ retValue = new BacklightResource();
+ break;
+ case SystemButtonType:
+ retValue = new SystemButtonResource();
+ break;
+ case LockButtonType:
+ retValue = new LockButtonResource();
+ break;
+ case ScaleButtonType:
+ retValue = new ScaleButtonResource();
+ break;
+ case SnapButtonType:
+ retValue = new SnapButtonResource();
+ break;
+ case LensCoverType:
+ retValue = new LensCoverResource();
+ break;
+ case NumberOfTypes:
+ return NULL;
+ }
+
+ if( retValue )
+ {
+ retValue->setOptional(optional);
+ }
+ else
+ {
+ printf("Unknown resource type - %d\n", resource);
+ }
+
+ return retValue;
+}
+
+ResourceType Client::getResourceType(uint32_t resource)
+{
+ switch( resource )
+ {
+ case RES_AUDIO_PLAYBACK:
+ return AudioPlaybackType;
+ case RES_VIDEO_PLAYBACK:
+ return VideoPlaybackType;
+ case RES_AUDIO_RECORDING:
+ return AudioRecorderType;
+ case RES_VIDEO_RECORDING:
+ return VideoRecorderType;
+ case RES_VIBRA:
+ return VibraType;
+ case RES_LEDS:
+ return LedsType;
+ case RES_BACKLIGHT:
+ return BacklightType;
+ case RES_SYSTEM_BUTTON:
+ return SystemButtonType;
+ case RES_LOCK_BUTTON:
+ return LockButtonType;
+ case RES_SCALE_BUTTON:
+ return ScaleButtonType;
+ case RES_SNAP_BUTTON:
+ return SnapButtonType;
+ case RES_LENS_COVER:
+ return LensCoverType;
+ }
+
+ return NumberOfTypes;
+}
+
+void Client::resourceAcquiredHandler(const QList<ResourceType>& /*grantedResList*/)
+{
+ timeStatAcq.markEnd(false);
+ testState = TestRelease;
+}
+
+void Client::resourceDeniedHandler()
+{
+/* if( timeStat.markEnd() )
+ {
+ timeStat.report();
+ }*/
+}
+
+void Client::resourceLostHandler()
+{
+/* if( timeStat.markEnd() )
+ {
+ timeStat.report();
+ }*/
+}
+
+void Client::resourceReleasedHandler()
+{
+ timeStatRel.markEnd(false);
+ testState = TestFinished;
+}
+
+void Client::timerEvent(QTimerEvent*)
+{
+ if( firstTime )
+ {
+ firstTime = false;
+ timeStatTotal.markStart();
+ initialize();
+ }
+
+ switch( testState )
+ {
+ case TestFinished:
+ if( testCounter == totalTestCount )
+ {
+ cleanup();
+ timeStatTotal.markEnd(false);
+ puts("\n*** RESULTS ***");
+ printf("Total failed: %d/%d\n", failed, totalTestCount);
+ printf("Total time : %.2f ms\n", timeStatTotal.caseTime);
+ printf("Average time: %.2f ms (%.2f ms)\n", timeStatTotal.caseTime / (double)totalTestCount, timeStatTotal.caseTime / (double)(totalTestCount*2));
+ printf("Acquire:\n\tAverage: %.2f ms\n\tMin : %.2f ms\n\tMax : %.2f ms\n", timeStatAcq.totalTime / (double)timeStatAcq.caseCount, timeStatAcq.totalMin, timeStatAcq.totalMax);
+ printf("Release:\n\tAverage: %.2f ms\n\tMin : %.2f ms\n\tMax : %.2f ms\n", timeStatRel.totalTime / (double)timeStatRel.caseCount, timeStatRel.totalMin, timeStatRel.totalMax);
+ timeStatAcq.exportData(qPrintable(reportAcquire));
+ timeStatRel.exportData(qPrintable(reportRelease));
+ QMetaObject::invokeMethod(QCoreApplication::instance(), "quit");
+ }
+ else
+ {
+ testCounter++;
+ testState = TestStart;
+ }
+ break;
+ case TestWaiting:
+ break;
+ case TestStart:
+ testState = TestAcquire;
+ printf("\rRunning round %d of %d ... ", testCounter, totalTestCount);
+ fflush(stdout);
+ break;
+ case TestAcquire:
+ timeStatAcq.markStart();
+ if( !resourceSet || !resourceSet->acquire() )
+ {
+ timeStatAcq.markEnd(true);
+ testState = TestFinished;
+ failed++;
+ }
+ else
+ testState = TestWaiting;
+ break;
+ case TestRelease:
+ timeStatRel.markStart();
+ if( !resourceSet || !resourceSet->release() )
+ {
+ timeStatRel.markEnd(true);
+ testState = TestFinished;
+ failed++;
+ }
+ else
+ testState = TestWaiting;
+ break;
+ }
+}
diff --git a/tests/test-performance/test-resourceqt-performance/client.h b/tests/test-performance/test-resourceqt-performance/client.h
new file mode 100644
index 0000000..c7ecb30
--- /dev/null
+++ b/tests/test-performance/test-resourceqt-performance/client.h
@@ -0,0 +1,175 @@
+#ifndef _CLIENT_H_
+#define _CLIENT_H_
+
+#include <QList>
+#include <QObject>
+
+#include <policy/resource-set.h>
+#include <sys/time.h>
+
+#define RES_AUDIO_PLAYBACK (1<<0)
+#define RES_VIDEO_PLAYBACK (1<<1)
+#define RES_AUDIO_RECORDING (1<<2)
+#define RES_VIDEO_RECORDING (1<<3)
+#define RES_VIBRA (1<<4)
+#define RES_LEDS (1<<5)
+#define RES_BACKLIGHT (1<<6)
+#define RES_SYSTEM_BUTTON (1<<7)
+#define RES_LOCK_BUTTON (1<<8)
+#define RES_SCALE_BUTTON (1<<9)
+#define RES_SNAP_BUTTON (1<<10)
+#define RES_LENS_COVER (1<<11)
+
+class TimeStat
+{
+public:
+ double totalTime;
+ double caseTime;
+ double totalMax;
+ double totalMin;
+ int caseCount;
+
+ TimeStat()
+ {
+ running = false;
+ totalTime = 0;
+ caseTime = 0;
+ caseCount = 0;
+ totalMax = 0;
+ totalMin = 9999999999.;
+ };
+
+ inline void markStart()
+ {
+ if( running )
+ return;
+
+ running = true;
+ gettimeofday(&start, NULL);
+ }
+
+ inline void markEnd(bool failed)
+ {
+ if( !running )
+ return;
+
+ gettimeofday(&end, NULL);
+
+ running = false;
+
+ timevalSub(&end, &start, &end);
+ caseTime = end.tv_sec * 1000.0 + end.tv_usec / 1000.0;
+
+ if( !failed )
+ {
+ totalMax = (totalMax < caseTime) ? caseTime : totalMax;
+ totalMin = (totalMin > caseTime) ? caseTime : totalMin;
+ totalTime += caseTime;
+ data.push_back(caseTime);
+ caseCount++;
+ }
+ }
+
+ void exportData(const char* name)
+ {
+ FILE* f = fopen(name, "wt");
+
+ fprintf(f, "Cnt;%d\n", caseCount);
+ fprintf(f, "Tot;%.4f\n", totalTime);
+ fprintf(f, "Max;%.4f\n", totalMax);
+ fprintf(f, "Min;%.4f\n", totalMin);
+ fprintf(f, "Avg;%.4f\n", totalTime / (double)caseCount);
+ int pos = 0;
+ DataList::iterator it;
+ for( it = data.begin(); it != data.end(); ++it )
+ {
+ fprintf(f, "%d;%.4f\n", ++pos, *it);
+ }
+ fclose(f);
+ }
+
+private:
+ typedef QList<double> DataList;
+
+ DataList data;
+ bool running;
+ struct timeval start;
+ struct timeval end;
+
+
+ void timevalSub(struct timeval *a, struct timeval *b, struct timeval *diff)
+ {
+ diff->tv_sec = a->tv_sec - b->tv_sec;
+ if( a->tv_usec < b->tv_usec )
+ {
+ diff->tv_sec--;
+ diff->tv_usec = 1000000 - b->tv_usec + a->tv_usec;
+ }
+ else
+ diff->tv_usec = a->tv_usec - b->tv_usec;
+ }
+};
+
+class Client : public QObject
+{
+ Q_OBJECT
+
+public:
+ static uint32_t parseResourceList(QString resourceListStr);
+
+public:
+ Client(int testCnt, QString appClass, uint32_t all, uint32_t optional);
+ ~Client();
+
+ bool initialize();
+ bool cleanup();
+ int getFailed() { return failed; }
+
+ double getAcquireAverage() { return timeStatAcq.totalTime / (double)timeStatAcq.caseCount; }
+ double getReleaseAverage() { return timeStatRel.totalTime / (double)timeStatRel.caseCount; }
+
+private slots:
+ void resourceAcquiredHandler(const QList<ResourcePolicy::ResourceType>& grantedResList);
+ void resourceDeniedHandler();
+ void resourceLostHandler();
+ void resourceReleasedHandler();
+
+protected:
+ void timerEvent(QTimerEvent *e);
+
+private:
+ enum TestState
+ {
+ TestFinished = 0,
+ TestStart,
+ TestAcquire,
+ TestRelease,
+ TestWaiting
+ };
+
+ QString reportAcquire;
+ QString reportRelease;
+ TestState testState;
+ int testCounter;
+ int mainTimerID;
+ QString applicationClass;
+ TimeStat timeStatAcq;
+ TimeStat timeStatRel;
+ TimeStat timeStatTotal;
+ bool firstTime;
+
+ uint32_t allResources;
+ uint32_t optionalResources;
+
+ int failed;
+ int totalTestCount;
+
+ ResourcePolicy::ResourceSet* resourceSet;
+
+ ResourcePolicy::Resource* allocateResource(ResourcePolicy::ResourceType resource, bool optional);
+ ResourcePolicy::ResourceType getResourceType(uint32_t resource);
+
+ void createSet(uint32_t list, uint32_t optional);
+};
+
+#endif
diff --git a/tests/test-performance/test-resourceqt-performance/test-resourceqt-performance.cpp b/tests/test-performance/test-resourceqt-performance/test-resourceqt-performance.cpp
new file mode 100644
index 0000000..69648b0
--- /dev/null
+++ b/tests/test-performance/test-resourceqt-performance/test-resourceqt-performance.cpp
@@ -0,0 +1,116 @@
+#include <QtCore/QCoreApplication>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <stdlib.h>
+#include <errno.h>
+#include <libgen.h>
+#include <getopt.h>
+#include "client.h"
+
+class ConfigParser
+{
+public:
+ ConfigParser()
+ {
+ exitCode = 0;
+ exitFlag = false;
+
+ resourcesAll = 0;
+ resourcesOptional = 0;
+ repeatCount = 100;
+
+ parseConfig();
+ }
+
+public:
+ bool exitFlag;
+ int exitCode;
+
+ int repeatCount;
+ uint32_t resourcesAll;
+ uint32_t resourcesOptional;
+ double timeLimit;
+ QString applicationClass;
+
+private:
+ void parseConfig()
+ {
+ QSettings settings("/usr/lib/libresourceqt-performance-tests/test-resourceqt-performance.ini", QSettings::IniFormat);
+
+ settings.beginGroup("config");
+ QString resAll = settings.value("AllResources", "AudioPlayback,VideoPlayback").toString();
+ QString resOpt = settings.value("OptionalResources", "").toString();
+ QString appClass = settings.value("ApplicationClass", "player").toString().toLower();
+ repeatCount = settings.value("TestCount", 100).toInt();
+ settings.endGroup();
+
+ settings.beginGroup("main");
+ timeLimit = settings.value("limit", 80.0).toDouble();
+ settings.endGroup();
+
+ resourcesAll = Client::parseResourceList(resAll);
+ resourcesOptional = Client::parseResourceList(resOpt);
+ applicationClass = parseClassString(qPrintable(appClass));
+
+ if( applicationClass.isEmpty() )
+ {
+ printf("Wrong application class in configuration file! Using default ...\n");
+ applicationClass = "player";
+ }
+
+ if( !resourcesAll )
+ {
+ resAll = "AudioPlayback,VideoPlayback";
+ resourcesAll = Client::parseResourceList(resAll);
+
+ printf("No resources found in configuration file! Using defaults ...\n");
+ }
+
+ if( (resourcesAll | resourcesOptional) != resourcesAll )
+ {
+ printf("Optional resources are not subset of all resources!\n");
+ exitFlag = true;
+ exitCode = 1;
+ }
+ }
+
+ const char* parseClassString(const char *str)
+ {
+ if( strcmp(str, "call") && strcmp(str, "camera") && strcmp(str, "ringtone") && strcmp(str, "alarm") && strcmp(str, "navigator") && strcmp(str, "game")
+ && strcmp(str, "player") && strcmp(str, "event") && strcmp(str, "background") )
+ {
+ printf("Invalid class '%s'", str);
+ return NULL;
+ }
+
+ return str;
+ }
+};
+
+int main(int argc, char *argv[])
+{
+ ConfigParser parser;
+
+ if( parser.exitFlag )
+ return parser.exitCode;
+
+ QCoreApplication app(argc, argv);
+ Client client(parser.repeatCount, parser.applicationClass, parser.resourcesAll, parser.resourcesOptional);
+ app.exec();
+
+ int retval = client.getFailed();
+ if( retval > 0 )
+ printf("One or more test iterations failed!\n");
+
+ int oldval = retval;
+ retval += client.getAcquireAverage() > parser.timeLimit ? 100 : 0;
+ if( retval > oldval )
+ printf("Acquire average time is higher than limit (%.2f/%.2f ms) !\n", client.getAcquireAverage(), parser.timeLimit);
+
+ oldval = retval;
+ retval += client.getReleaseAverage() > parser.timeLimit ? 100 : 0;
+ if( retval > oldval )
+ printf("Release average time is higher than limit (%.2f/%.2f ms) !\n", client.getReleaseAverage(), parser.timeLimit);
+
+ return retval;
+}
diff --git a/tests/test-performance/test-resourceqt-performance/test-resourceqt-performance.pro b/tests/test-performance/test-resourceqt-performance/test-resourceqt-performance.pro
new file mode 100644
index 0000000..01c9573
--- /dev/null
+++ b/tests/test-performance/test-resourceqt-performance/test-resourceqt-performance.pro
@@ -0,0 +1,24 @@
+include(../../../common.pri)
+
+TEMPLATE = app
+TARGET = test-resourceqt-performance
+MOC_DIR = .moc
+OBJECTS_DIR = .obj
+DEPENDPATH += .
+QT = core
+CONFIG += console
+CONFIG -= app_bundle
+
+INCLUDEPATH += $${LIBRESOURCEINC}
+QMAKE_CXXFLAGS += -Wall
+LIBS += -L$${LIBRESOURCEQT}/build -lresourceqt -L$${LIBDBUSQEVENTLOOP}/build -ldbus-qeventloop
+
+# Input
+HEADERS = client.h
+SOURCES += test-resourceqt-performance.cpp client.cpp
+
+QMAKE_DISTCLEAN += -r .moc .obj
+
+# Install options
+target.path = /usr/lib/libresourceqt-performance-tests/
+INSTALLS = target
diff --git a/tests/test-performance/tests.xml b/tests/test-performance/tests.xml
new file mode 100644
index 0000000..852e2eb
--- /dev/null
+++ b/tests/test-performance/tests.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<testdefinition version="0.1">
+ <suite name="libresourceqt-performance-tests" domain="Multimedia Middleware">
+ <set name="libresourceqt-performance-tests" feature="Resource policy">
+
+ <case name="no-dbus-load" type="Performance" level="Component" subfeature="libresource Qt dbus performance" description="Testcase without dbus spamming" timeout="120">
+ <step expected_result="0">/usr/lib/libresourceqt-performance-tests/test-resourceqt-performance-runner.sh 0</step>
+ </case>
+
+ <case name="small-dbus-load" type="Performance" level="Component" subfeature="libresource Qt dbus performance" description="Testcase with 5 dbus spamming threads, message size 50 bytes" timeout="120">
+ <step expected_result="0">/usr/lib/libresourceqt-performance-tests/test-resourceqt-performance-runner.sh 1</step>
+ </case>
+
+ <case name="medium-dbus-load" type="Performance" level="Component" subfeature="libresource Qt dbus performance" description="Testcase with 10 dbus spamming threads, message size 50 bytes" timeout="120">
+ <step expected_result="0">/usr/lib/libresourceqt-performance-tests/test-resourceqt-performance-runner.sh 2</step>
+ </case>
+
+ <case name="heavy-dbus-load" type="Performance" level="Component" subfeature="libresource Qt dbus performance" description="Testcase with 20 dbus spamming threads, message size 50 bytes" timeout="120">
+ <step expected_result="0">/usr/lib/libresourceqt-performance-tests/test-resourceqt-performance-runner.sh 3</step>
+ </case>
+
+ <case name="very-heavy-dbus-load" type="Performance" level="Component" subfeature="libresource Qt dbus performance" description="Testcase with 20 dbus spamming threads, message size 150 bytes" timeout="240">
+ <step expected_result="0">/usr/lib/libresourceqt-performance-tests/test-resourceqt-performance-runner.sh 4</step>
+ </case>
+
+ <get>
+ <file>/tmp/resourceqt-performance.html</file>
+ </get>
+
+ <environments>
+ <scratchbox>false</scratchbox>
+ <hardware>true</hardware>
+ </environments>
+
+ </set>
+ </suite>
+</testdefinition>