Index: kdevplatform/project/abstractfilemanagerplugin.h =================================================================== --- kdevplatform/project/abstractfilemanagerplugin.h +++ kdevplatform/project/abstractfilemanagerplugin.h @@ -103,6 +103,20 @@ */ KDirWatch* projectWatcher( IProject* project ) const; + /** + * @return the number of watched directories for the given @p project. + * + * Stock KDirWatch doesn't currently have a method to query the number of items it watches + * but it will be watching just about everything in the project so this returns the file+folder + * count as a reasonable approximation. + */ + int watchedItems( IProject* project ) const; + + /** + * tell the plugin that the given @p project is going to be closed. + */ + void projectClosing( IProject *project ); + Q_SIGNALS: void reloadedFileItem(KDevelop::ProjectFileItem* file); void reloadedFolderItem(KDevelop::ProjectFolderItem* folder); Index: kdevplatform/project/abstractfilemanagerplugin.cpp =================================================================== --- kdevplatform/project/abstractfilemanagerplugin.cpp +++ kdevplatform/project/abstractfilemanagerplugin.cpp @@ -27,6 +27,9 @@ #include #include #include +#ifdef TIME_IMPORT_JOB +#include +#endif #include #include @@ -117,7 +120,18 @@ } m_projectJobs.remove(project); } +#ifdef TIME_IMPORT_JOB + QElapsedTimer timer; + if (m_watchers.contains(project)) { + timer.start(); + } +#endif delete m_watchers.take(project); +#ifdef TIME_IMPORT_JOB + if (timer.isValid()) { + qCInfo(FILEMANAGER) << "Deleting dir watcher took" << timer.elapsed() / 1000.0 << "seconds for project" << project->name(); + } +#endif m_filters.remove(project); } @@ -661,6 +675,16 @@ return d->m_watchers.value( project, nullptr ); } +int AbstractFileManagerPlugin::watchedItems( IProject* project ) const +{ + return project->fileSet().size(); +} + +void AbstractFileManagerPlugin::projectClosing( IProject *project ) +{ + d->projectClosing(project); +} + //END Plugin #include "moc_abstractfilemanagerplugin.cpp" Index: kdevplatform/project/tests/CMakeLists.txt =================================================================== --- kdevplatform/project/tests/CMakeLists.txt +++ kdevplatform/project/tests/CMakeLists.txt @@ -21,3 +21,12 @@ KDev::Tests Qt5::QuickWidgets ) + +add_executable(abstractfilemanagerpluginimportbenchmark + abstractfilemanagerpluginimportbenchmark.cpp +) +ecm_mark_nongui_executable(abstractfilemanagerpluginimportbenchmark) +target_link_libraries(abstractfilemanagerpluginimportbenchmark + KDev::Project + KDev::Tests +) Index: kdevplatform/project/tests/abstractfilemanagerpluginimportbenchmark.cpp =================================================================== --- /dev/null +++ kdevplatform/project/tests/abstractfilemanagerpluginimportbenchmark.cpp @@ -0,0 +1,164 @@ +/* This file is part of KDevelop + Copyright 2017 René J.V. Bertin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace KDevelop; + +class TestFileManagerPlugin : public AbstractFileManagerPlugin +{ + Q_OBJECT +public: + TestFileManagerPlugin(QObject* parent = nullptr) + : AbstractFileManagerPlugin({}, parent) + {} + + using AbstractFileManagerPlugin::watchedItems; + + using AbstractFileManagerPlugin::projectClosing; +}; + +class AFMPBenchmark : public QObject { + Q_OBJECT +public: + AFMPBenchmark(TestFileManagerPlugin* manager, const QString& path, QObject* parent) + : QObject(parent) + { + if (QFileInfo(path).isDir()) { + m_manager = manager; + m_project = new TestProject(Path(path)); + } else { + qWarning() << path << "is not a directory, ignoring"; + m_project = nullptr; + } + } + + void start() + { + if (!m_project) { + return; + } + m_projectNumber = s_count++; + qInfo() << "Starting import of project #" << m_projectNumber << "at" << m_project->path(); + m_timer.start(); + auto root = m_manager->import(m_project); + int elapsed = m_timer.elapsed(); + qInfo() << "\tcreating dirwatcher took" + << elapsed / 1000.0 << "seconds"; + auto import = m_manager->createImportJob(root); + QObject::connect(import, &KJob::finished, this, &AFMPBenchmark::projectImportDone); + m_timer.restart(); + import->start(); + } + + void projectClosing() + { + m_timer.restart(); + m_manager->projectClosing(m_project); + int elapsed = m_timer.elapsed(); + qInfo() << "\tclosing project" << m_projectNumber << ":" << elapsed / 1000.0 << "seconds"; + } + + TestFileManagerPlugin* m_manager; + TestProject* m_project; + QElapsedTimer m_timer; + int m_projectNumber; + + static int s_count; + +Q_SIGNALS: + void finished(); + +private Q_SLOTS: + void projectImportDone(KJob* job) + { + Q_UNUSED(job); + int elapsed = m_timer.elapsed(); + qInfo() << "imported project" << m_projectNumber + << "with" << m_project->fileSet().size() + << "files (watched:" << m_manager->watchedItems(m_project) << "):" + << elapsed / 1000.0 << "seconds"; + + s_count -= 1; + if (s_count <= 0) { + qInfo() << "Done."; + emit finished(); + } + } + +}; + +int AFMPBenchmark::s_count = 0; + +int main(int argc, char** argv) +{ + if (argc < 2) { + qWarning() << "Usage:" << argv[0] << "projectDir1 [...projectDirN]"; + return 1; + } + QCoreApplication app(argc, argv); + + AutoTestShell::init(); + auto core = TestCore::initialize(Core::NoUi); + auto manager = new TestFileManagerPlugin(core); + + const char *kdwMethod[] = {"FAM", "Inotify", "Stat", "QFSWatch"}; + qInfo() << "KDirWatch backend:" << kdwMethod[KDirWatch().internalMethod()]; + + QList benchmarks; + + for (int i = 1 ; i < argc ; ++i) { + const auto benchmark = new AFMPBenchmark(manager, QString::fromUtf8(argv[i]), core); + benchmarks << benchmark; + QObject::connect(benchmark, &AFMPBenchmark::finished, + &app, [&benchmarks] { + for (auto benchmark : benchmarks) { + benchmark->projectClosing(); + } + QCoreApplication::instance()->quit(); + }); + } + for (auto benchmark : benchmarks) { + benchmark->start(); + } + + if (benchmarks.first()->s_count > 0) { + return app.exec(); + } + return 1; +} + +#include "abstractfilemanagerpluginimportbenchmark.moc"