Browse Source

Added performance unit test for the plugin framework.

Sascha Zelzer 12 years ago
parent
commit
2bb48f0b36

+ 1 - 0
Libs/Core/CMakeLists.txt

@@ -52,6 +52,7 @@ set(KIT_SRCS
   ctkErrorLogStreamMessageHandler.h
   ctkException.cpp
   ctkException.h
+  ctkHighPrecisionTimer.h
   ctkLogger.cpp
   ctkLogger.h
   ctkHistogram.cpp

+ 155 - 0
Libs/Core/ctkHighPrecisionTimer.h

@@ -0,0 +1,155 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed 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
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+#ifndef CTKHIGHPRECISIONTIMER_H
+#define CTKHIGHPRECISIONTIMER_H
+
+
+#include <qglobal.h>
+
+#ifdef Q_OS_UNIX
+#include <time.h>
+#include <unistd.h>
+#elif defined(Q_OS_WIN)
+#include <windows.h>
+#else
+#include <QTime>
+#endif
+
+#include "ctkException.h"
+
+/**
+ * \ingroup Core
+ *
+ *
+ * @brief A fast and high precision timer.
+ *
+ * This class provides a fast and high precision timer depending on
+ * platform specific API. It can be used as a QTime replacement for
+ * runtime measurements with a minimal performance overhead.
+ */
+class ctkHighPrecisionTimer {
+
+public:
+
+  inline ctkHighPrecisionTimer();
+
+  inline void start();
+
+  inline qint64 elapsedMilli();
+
+  inline qint64 elapsedMicro();
+
+private:
+
+#ifdef _POSIX_MONOTONIC_CLOCK
+  timespec startTime;
+#elif defined(Q_OS_WIN)
+  LARGE_INTEGER timerFrequency;
+  LARGE_INTEGER startTime;
+#else
+  QTime startTime;
+#endif
+};
+
+#ifdef _POSIX_MONOTONIC_CLOCK
+
+inline ctkHighPrecisionTimer::ctkHighPrecisionTimer()
+{
+  startTime.tv_nsec = 0;
+  startTime.tv_sec = 0;
+}
+
+inline void ctkHighPrecisionTimer::start()
+{
+  clock_gettime(CLOCK_MONOTONIC, &startTime);
+}
+
+inline qint64 ctkHighPrecisionTimer::elapsedMilli()
+{
+  timespec current;
+  clock_gettime(CLOCK_MONOTONIC, &current);
+  return (static_cast<qint64>(current.tv_sec)*1000 + current.tv_nsec/1000/1000) -
+      (static_cast<qint64>(startTime.tv_sec)*1000 + startTime.tv_nsec/1000/1000);
+}
+
+inline qint64 ctkHighPrecisionTimer::elapsedMicro()
+{
+  timespec current;
+  clock_gettime(CLOCK_MONOTONIC, &current);
+  return (static_cast<qint64>(current.tv_sec)*1000*1000 + current.tv_nsec/1000) -
+      (static_cast<qint64>(startTime.tv_sec)*1000*1000 + startTime.tv_nsec/1000);
+}
+
+#elif defined(Q_OS_WIN)
+
+inline ctkHighPrecisionTimer::ctkHighPrecisionTimer()
+{
+  if (!QueryPerformanceFrequency(&timerFrequency))
+    throw ctkRuntimeException("QueryPerformanceFrequency() failed");
+}
+
+inline void ctkHighPrecisionTimer::start()
+{
+  //DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), 0);
+  QueryPerformanceCounter(&startTime);
+  //SetThreadAffinityMask(GetCurrentThread(), oldmask);
+}
+
+inline qint64 ctkHighPrecisionTimer::elapsedMilli()
+{
+  LARGE_INTEGER current;
+  QueryPerformanceCounter(&current);
+  return (current.QuadPart - startTime.QuadPart) / (timerFrequency.QuadPart / 1000);
+}
+
+inline qint64 ctkHighPrecisionTimer::elapsedMicro()
+{
+  LARGE_INTEGER current;
+  QueryPerformanceCounter(&current);
+  return (current.QuadPart - startTime.QuadPart) / (timerFrequency.QuadPart / (1000*1000));
+}
+
+#else
+
+inline ctkHighPrecisionTimer::ctkHighPrecisionTimer()
+  : startTime(QTime::currentTime())
+{
+}
+
+inline void ctkHighPrecisionTimer::start()
+{
+  startTime = QTime::currentTime();
+}
+
+inline qint64 ctkHighPrecisionTimer::elapsedMilli()
+{
+  return startTime.elapsed();
+}
+
+inline qint64 ctkHighPrecisionTimer::elapsedMicro()
+{
+  return startTime.elapsed() * 1000;
+}
+
+#endif
+
+#endif // CTKHIGHPRECISIONTIMER_H

+ 1 - 0
Libs/PluginFramework/Testing/CMakeLists.txt

@@ -23,6 +23,7 @@ set(metatypetest_plugins
 add_subdirectory(org.commontk.pluginfwtest)
 add_subdirectory(FrameworkTestPlugins)
 
+add_subdirectory(org.commontk.pluginfwtest.perf)
 add_subdirectory(org.commontk.configadmintest)
 add_subdirectory(org.commontk.eventadmintest)
 

+ 0 - 140
Libs/PluginFramework/Testing/Cpp/ctkPluginFrameworkTestMain.cpp

@@ -1,140 +0,0 @@
-/*=============================================================================
-
-  Library: CTK
-
-  Copyright (c) 2010 German Cancer Research Center,
-    Division of Medical and Biological Informatics
-
-  Licensed 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
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-=============================================================================*/
-
-#include <QCoreApplication>
-#include <QDirIterator>
-#include <QTest>
-#include <QThread>
-#include <QDebug>
-
-#include <ctkPluginContext.h>
-#include <ctkPluginConstants.h>
-#include <ctkPluginFrameworkFactory.h>
-#include <ctkPluginFramework.h>
-#include <ctkPluginException.h>
-#include <ctkServiceReference.h>
-
-#include "ctkTestSuiteInterface.h"
-
-class TestRunner : public QThread
-{
-public:
-
-  TestRunner(ctkPluginContext* context, long testPluginId, int argc, char** argv)
-    : context(context), testPluginId(testPluginId), argc(argc), argv(argv)
-  {
-
-  }
-
-  void run()
-  {
-    // start the main test plugin which registers the test suites (QObject classes)
-    QSharedPointer<ctkPlugin> fwTest = context->getPlugin(testPluginId);
-    fwTest->start();
-
-    QList<ctkServiceReference> refs = context->getServiceReferences<ctkTestSuiteInterface>();
-
-    int result = 0;
-    foreach(ctkServiceReference ref, refs)
-    {
-      result += QTest::qExec(context->getService(ref), argc, argv);
-      if (result > 0) break;
-    }
-
-    if (result > 0) QCoreApplication::exit(result);
-  }
-
-private:
-
-  ctkPluginContext* context;
-  long testPluginId;
-  int argc;
-  char** argv;
-};
-
-int main(int argc, char** argv)
-{
-  QCoreApplication app(argc, argv);
-
-  app.setOrganizationName("CTK");
-  app.setOrganizationDomain("commontk.org");
-  app.setApplicationName("ctkPluginFrameworkCppTests");
-
-  QString pluginDir;
-#ifdef CMAKE_INTDIR
-  pluginDir = qApp->applicationDirPath() + "/../test_plugins/" CMAKE_INTDIR "/";
-#else
-  pluginDir = qApp->applicationDirPath() + "/test_plugins/";
-#endif
-
-  QApplication::addLibraryPath(pluginDir);
-
-  ctkProperties fwProps;
-  fwProps.insert(ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN, ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
-  fwProps.insert("pluginfw.testDir", pluginDir);
-  ctkPluginFrameworkFactory fwFactory(fwProps);
-  QSharedPointer<ctkPluginFramework> framework = fwFactory.getFramework();
-  framework->start();
-
-  ctkPluginContext* context = framework->getPluginContext();
-
-  long fwTestPluginId = -1;
-  QStringList libFilter;
-  libFilter << "*.dll" << "*.so" << "*.dylib";
-  QDirIterator dirIter(pluginDir, libFilter, QDir::Files);
-  while(dirIter.hasNext())
-  {
-    dirIter.next();
-    if (dirIter.fileName().contains("org_commontk_pluginfwtest"))
-    {
-      try
-      {
-        fwTestPluginId = context->installPlugin(QUrl::fromLocalFile(dirIter.filePath()).toString())->getPluginId();
-        break;
-      }
-      catch (const ctkPluginException& e)
-      {
-        qCritical() << e.what();
-      }
-    }
-  }
-
-  if (fwTestPluginId < 0)
-  {
-    qCritical() << "Could not find the plugin framework test plugin: org.commontk.pluginfwtest";
-  }
-
-//  QList<ctkServiceReference> refs = context->getServiceReferences("ctkTestSuiteInterface");
-
-//  int result = 0;
-//  foreach(ctkServiceReference ref, refs)
-//  {
-//    result = QTest::qExec(context->getService(ref), argc, argv);
-//  }
-
-//  return result;
-
-  TestRunner runner(context, fwTestPluginId, argc, argv);
-  runner.connect(&runner, SIGNAL(finished()), &app, SLOT(quit()));
-  runner.start();
-
-  return app.exec();
-}

+ 4 - 1
Libs/PluginFramework/Testing/Cpp/ctkPluginFrameworkTestRunner.cpp

@@ -165,7 +165,9 @@ public:
     while(dirIter.hasNext())
     {
       dirIter.next();
-      if (dirIter.fileName().contains(name))
+      QString fileName = dirIter.fileName().mid(3); // strip the "lib" prefix
+      fileName.truncate(fileName.lastIndexOf('.')); // remove the suffix
+      if (fileName == name)
       {
         try
         {
@@ -253,6 +255,7 @@ void ctkPluginFrameworkTestRunner::init(const ctkProperties& fwProps)
   foreach(ctkPluginFrameworkTestRunnerPrivate::InstallCandPair candidate,
           d->installCandidates)
   {
+    qDebug() << "Installing" << candidate.first << "," << candidate.second;
     d->installPlugin(candidate.first, candidate.second);
   }
 }

+ 58 - 0
Libs/PluginFramework/Testing/org.commontk.pluginfwtest.perf/CMakeLists.txt

@@ -0,0 +1,58 @@
+project(org_commontk_pluginfwtest_perf)
+
+set(PLUGIN_export_directive "org_commontk_pluginfwtest_perf_EXPORT")
+
+set(PLUGIN_SRCS
+  ctkPluginFrameworkTestPerfActivator_p.h
+  ctkPluginFrameworkTestPerfActivator.cpp
+  ctkPluginFrameworkPerfRegistryTestSuite_p.h
+  ctkPluginFrameworkPerfRegistryTestSuite.cpp
+)
+
+set(PLUGIN_MOC_SRCS
+  ctkPluginFrameworkTestPerfActivator_p.h
+  ctkPluginFrameworkPerfRegistryTestSuite_p.h
+)
+
+set(PLUGIN_UI_FORMS
+  
+)
+
+set(PLUGIN_resources
+  
+)
+
+ctkFunctionGetTargetLibraries(PLUGIN_target_libraries)
+
+if(UNIX)
+  list(APPEND PLUGIN_target_libraries rt)
+endif()
+
+ctkMacroBuildPlugin(
+  NAME ${PROJECT_NAME}
+  EXPORT_DIRECTIVE ${PLUGIN_export_directive}
+  SRCS ${PLUGIN_SRCS}
+  MOC_SRCS ${PLUGIN_MOC_SRCS}
+  UI_FORMS ${PLUGIN_UI_FORMS}
+  RESOURCES ${PLUGIN_resources}
+  TARGET_LIBRARIES ${PLUGIN_target_libraries}
+  TEST_PLUGIN
+)
+
+# =========== Build the test executable ===============
+set(SRCS
+  ctkPluginFrameworkTestPerfMain.cpp
+)
+
+set(test_executable ${PROJECT_NAME}CppTests)
+
+add_executable(${test_executable} ${SRCS})
+target_link_libraries(${test_executable}
+  ${fw_lib}
+  ${fwtestutil_lib}
+)
+
+add_dependencies(${test_executable} ${PROJECT_NAME})
+
+add_test(${PROJECT_NAME}Tests ${CPP_TEST_PATH}/${test_executable})
+set_property(TEST ${PROJECT_NAME}Tests PROPERTY LABELS ${PROJECT_NAME})

+ 219 - 0
Libs/PluginFramework/Testing/org.commontk.pluginfwtest.perf/ctkPluginFrameworkPerfRegistryTestSuite.cpp

@@ -0,0 +1,219 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed 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
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#include "ctkPluginFrameworkPerfRegistryTestSuite_p.h"
+
+#include <ctkPluginContext.h>
+#include <ctkServiceEvent.h>
+#include <ctkHighPrecisionTimer.h>
+
+#include <QTest>
+#include <QDebug>
+
+//----------------------------------------------------------------------------
+ctkPluginFrameworkPerfRegistryTestSuite::ctkPluginFrameworkPerfRegistryTestSuite(ctkPluginContext* context)
+  : QObject(0)
+  , pc(context)
+  , nListeners(100)
+  , nServices(1000)
+  , nRegistered(0)
+  , nUnregistering(0)
+  , nModified(0)
+{
+  this->setObjectName("ctkPluginFrameworkPerfRegistryTestSuite");
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkPerfRegistryTestSuite::initTestCase()
+{
+  qDebug() << "Initialize event counters";
+
+  nRegistered    = 0;
+  nUnregistering = 0;
+  nModified      = 0;
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkPerfRegistryTestSuite::cleanupTestCase()
+{
+  qDebug() << "Remove all service listeners";
+
+  for(int i = 0; i < listeners.size(); i++)
+  {
+    try
+    {
+      ctkServiceListener* l = listeners[i];
+      pc->disconnectServiceListener(l, "serviceChanged");
+    }
+    catch (const ctkException& e)
+    {
+      qDebug() << e.printStackTrace();
+    }
+  }
+  listeners.clear();
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkPerfRegistryTestSuite::testAddListeners()
+{
+  addListeners(nListeners);
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkPerfRegistryTestSuite::addListeners(int n)
+{
+  log() << "adding" << n << "service listeners";
+  for(int i = 0; i < n; i++)
+  {
+    ctkServiceListener* l = new ctkServiceListener(this);
+    try
+    {
+      listeners.push_back(l);
+      pc->connectServiceListener(l, "serviceChanged", "(perf.service.value>=0)");
+    }
+    catch (const ctkException& e)
+    {
+      qDebug() << e.printStackTrace();
+    }
+  }
+  log() << "listener count=" << listeners.size();
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkPerfRegistryTestSuite::testRegisterServices()
+{
+  qDebug() << "Register services, and check that we get #of services ("
+           << nServices << ") * #of listeners (" << nListeners << ")  REGISTERED events";
+
+  log() << "registering" << nServices << "services, listener count=" << listeners.size();
+
+  ctkHighPrecisionTimer t;
+  t.start();
+  registerServices(nServices);
+  int ms = t.elapsedMilli();
+  log() << "register took" << ms << "ms";
+  QVERIFY2(nServices * listeners.size() == nRegistered,
+           "# REGISTERED events must be same as # of registered services  * # of listeners");
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkPerfRegistryTestSuite::registerServices(int n)
+{
+  QString pid("my.service.%1");
+
+  for(int i = 0; i < n; i++)
+  {
+    ctkDictionary props;
+    props.insert("service.pid", pid.arg(i));
+    props.insert("perf.service.value", i+1);
+
+    QObject* service = new PerfTestService();
+    services.push_back(service);
+    ctkServiceRegistration reg =
+        pc->registerService<IPerfTestService>(service, props);
+    regs.push_back(reg);
+  }
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkPerfRegistryTestSuite::testModifyServices()
+{
+  qDebug() << "Modify all services, and check that we get #of services ("
+           << nServices << ") * #of listeners (" << nListeners << ")  MODIFIED "
+              << " events";
+
+  ctkHighPrecisionTimer t;
+  t.start();
+  modifyServices();
+  int ms = t.elapsedMilli();
+  log() << "modify took" << ms << "ms";
+  QVERIFY2(nServices * listeners.size() == nModified,
+           "# MODIFIED events must be same as # of modified services  * # of listeners");
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkPerfRegistryTestSuite::modifyServices()
+{
+  log() << "modifying " << regs.size() << "services, listener count=" << listeners.size();
+
+  for(int i = 0; i < regs.size(); i++)
+  {
+    ctkServiceRegistration reg = regs[i];
+    ctkDictionary props;
+    props.insert("perf.service.value", i * 2);
+    reg.setProperties(props);
+  }
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkPerfRegistryTestSuite::testUnregisterServices()
+{
+  qDebug() << "Unregister all services, and check that we get #of services ("
+           << nServices << ") * #of listeners (" << nListeners
+           << ")  UNREGISTERING events";
+
+  ctkHighPrecisionTimer t;
+  t.start();
+  unregisterServices();
+  int ms = t.elapsedMilli();
+  log() <<  "unregister took " << ms << "ms";
+  QVERIFY2(nServices * listeners.size() == nUnregistering, "# UNREGISTERING events must be same as # of (un)registered services * # of listeners");
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkPerfRegistryTestSuite::unregisterServices()
+{
+  log() << "unregistering " << regs.size() << " services, listener count="
+        << listeners.size();
+  for(int i = 0; i < regs.size(); i++)
+  {
+    ctkServiceRegistration reg = regs[i];
+    reg.unregister();
+  }
+  regs.clear();
+}
+
+
+//----------------------------------------------------------------------------
+ctkServiceListener::ctkServiceListener(ctkPluginFrameworkPerfRegistryTestSuite* ts)
+  : ts(ts)
+{
+}
+
+//----------------------------------------------------------------------------
+void ctkServiceListener::serviceChanged(const ctkServiceEvent& ev)
+{
+  switch(ev.getType())
+  {
+  case ctkServiceEvent::REGISTERED:
+    ts->nRegistered++;
+    break;
+  case ctkServiceEvent::UNREGISTERING:
+    ts->nUnregistering++;
+    break;
+  case ctkServiceEvent::MODIFIED:
+    ts->nModified++;
+    break;
+  default:
+    break;
+  }
+}

+ 117 - 0
Libs/PluginFramework/Testing/org.commontk.pluginfwtest.perf/ctkPluginFrameworkPerfRegistryTestSuite_p.h

@@ -0,0 +1,117 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed 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
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#ifndef CTKPLUGINFRAMEWORKPERFREGISTRYTESTSUITE_P_H
+#define CTKPLUGINFRAMEWORKPERFREGISTRYTESTSUITE_P_H
+
+#include "ctkTestSuiteInterface.h"
+#include "ctkServiceRegistration.h"
+
+#include <QDebug>
+
+class ctkPluginContext;
+class ctkServiceEvent;
+
+class ctkServiceListener;
+
+class ctkPluginFrameworkPerfRegistryTestSuite : public QObject, public ctkTestSuiteInterface
+{
+  Q_OBJECT
+  Q_INTERFACES(ctkTestSuiteInterface)
+
+private:
+
+  ctkPluginContext* pc;
+
+  int nListeners;
+  int nServices;
+
+  int nRegistered;
+  int nUnregistering;
+  int nModified;
+
+  QList<ctkServiceRegistration> regs;
+  QList<ctkServiceListener*> listeners;
+  QList<QObject*> services;
+
+public:
+
+  ctkPluginFrameworkPerfRegistryTestSuite(ctkPluginContext* context);
+
+  QDebug log()
+  {
+    return qDebug() << "registry_perf:";
+  }
+
+private:
+
+  friend class ctkServiceListener;
+
+  void addListeners(int n);
+  void registerServices(int n);
+  void modifyServices();
+  void unregisterServices();
+
+private Q_SLOTS:
+
+  void initTestCase();
+  void cleanupTestCase();
+
+  void testAddListeners();
+  void testRegisterServices();
+
+  void testModifyServices();
+  void testUnregisterServices();
+};
+
+class ctkServiceListener : public QObject
+{
+  Q_OBJECT
+
+private:
+
+  ctkPluginFrameworkPerfRegistryTestSuite* ts;
+
+public:
+
+  ctkServiceListener(ctkPluginFrameworkPerfRegistryTestSuite* ts);
+
+protected Q_SLOTS:
+
+  void serviceChanged(const ctkServiceEvent& ev);
+};
+
+struct IPerfTestService
+{
+  virtual ~IPerfTestService() {}
+};
+
+Q_DECLARE_INTERFACE(IPerfTestService, "org.commontk.test.PerfTestService")
+
+class PerfTestService : public QObject, public IPerfTestService
+{
+  Q_OBJECT
+  Q_INTERFACES(IPerfTestService)
+};
+
+
+#endif // CTKPLUGINFRAMEWORKPERFREGISTRYTESTSUITE_P_H

+ 58 - 0
Libs/PluginFramework/Testing/org.commontk.pluginfwtest.perf/ctkPluginFrameworkTestPerfActivator.cpp

@@ -0,0 +1,58 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed 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
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+#include "ctkPluginFrameworkTestPerfActivator_p.h"
+
+#include "ctkPluginFrameworkPerfRegistryTestSuite_p.h"
+
+#include <QtPlugin>
+
+
+//----------------------------------------------------------------------------
+ctkPluginFrameworkTestPerfActivator::ctkPluginFrameworkTestPerfActivator()
+  : perfTestSuite(0)
+{
+
+}
+
+//----------------------------------------------------------------------------
+ctkPluginFrameworkTestPerfActivator::~ctkPluginFrameworkTestPerfActivator()
+{
+  delete perfTestSuite;
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkTestPerfActivator::start(ctkPluginContext* context)
+{
+  perfTestSuite = new ctkPluginFrameworkPerfRegistryTestSuite(context);
+  context->registerService<ctkTestSuiteInterface>(perfTestSuite);
+}
+
+//----------------------------------------------------------------------------
+void ctkPluginFrameworkTestPerfActivator::stop(ctkPluginContext* context)
+{
+  Q_UNUSED(context);
+
+  delete perfTestSuite;
+  perfTestSuite = 0;
+}
+
+Q_EXPORT_PLUGIN2(org_commontk_pluginfwtest_perf, ctkPluginFrameworkTestPerfActivator)

+ 48 - 0
Libs/PluginFramework/Testing/org.commontk.pluginfwtest.perf/ctkPluginFrameworkTestPerfActivator_p.h

@@ -0,0 +1,48 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed 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
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#ifndef CTKPLUGINFRAMEWORKTESTPERFACTIVATOR_H
+#define CTKPLUGINFRAMEWORKTESTPERFACTIVATOR_H
+
+#include <ctkPluginActivator.h>
+
+
+class ctkPluginFrameworkTestPerfActivator : public QObject,
+    public ctkPluginActivator
+{
+  Q_OBJECT
+  Q_INTERFACES(ctkPluginActivator)
+
+public:
+
+  ctkPluginFrameworkTestPerfActivator();
+  ~ctkPluginFrameworkTestPerfActivator();
+
+  void start(ctkPluginContext* context);
+  void stop(ctkPluginContext* context);
+
+private:
+
+  QObject* perfTestSuite;
+};
+
+#endif // CTKPLUGINFRAMEWORKTESTPERFACTIVATOR_H

+ 61 - 0
Libs/PluginFramework/Testing/org.commontk.pluginfwtest.perf/ctkPluginFrameworkTestPerfMain.cpp

@@ -0,0 +1,61 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed 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
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+#include <QCoreApplication>
+
+
+#include <ctkPluginConstants.h>
+
+#include "ctkPluginFrameworkTestRunner.h"
+
+
+int main(int argc, char** argv)
+{
+  QCoreApplication app(argc, argv);
+
+  ctkPluginFrameworkTestRunner testRunner;
+
+  app.setOrganizationName("CTK");
+  app.setOrganizationDomain("commontk.org");
+  app.setApplicationName("ctkPluginFrameworkCppTests");
+
+  QString pluginDir;
+#ifdef CMAKE_INTDIR
+  pluginDir = qApp->applicationDirPath() + "/../test_plugins/" CMAKE_INTDIR "/";
+#else
+  pluginDir = qApp->applicationDirPath() + "/test_plugins/";
+#endif
+
+  testRunner.addPluginPath(pluginDir, false);
+  testRunner.addPlugin(pluginDir, "org_commontk_pluginfwtest_perf");
+  testRunner.startPluginOnRun("org.commontk.pluginfwtest.perf");
+
+  ctkProperties fwProps;
+  fwProps.insert(ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN, ctkPluginConstants::FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
+  fwProps.insert("pluginfw.testDir", pluginDir);
+
+#if defined(Q_CC_GNU) && ((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 5)))
+  fwProps.insert(ctkPluginConstants::FRAMEWORK_PLUGIN_LOAD_HINTS, QVariant::fromValue<QLibrary::LoadHints>(QLibrary::ExportExternalSymbolsHint));
+#endif
+
+  testRunner.init(fwProps);
+  return testRunner.run(argc, argv);
+}

+ 10 - 0
Libs/PluginFramework/Testing/org.commontk.pluginfwtest.perf/manifest_headers.cmake

@@ -0,0 +1,10 @@
+set(Plugin-ActivationPolicy "eager")
+set(Plugin-Name "Framework Registry Performance Test Suite")
+set(Plugin-Version "0.9")
+set(Plugin-Description "Test the performance of the service registry")
+set(Plugin-Vendor "CommonTK")
+set(Plugin-DocURL "http://www.commontk.org")
+set(Plugin-ContactAddress "http://www.commontk.org")
+set(Plugin-Category "test")
+set(Plugin-Copyright "German Cancer Research Center, Division of Medical and Biological Informatics")
+set(Plugin-License "http://www.apache.org/licenses/LICENSE-2.0.html")

+ 9 - 0
Libs/PluginFramework/Testing/org.commontk.pluginfwtest.perf/target_libraries.cmake

@@ -0,0 +1,9 @@
+#
+# See CMake/ctkFunctionGetTargetLibraries.cmake
+# 
+# This file should list the libraries required to build the current CTK plugin.
+# 
+
+set(target_libraries
+  CTKPluginFramework
+  )