File indexing completed on 2024-05-19 04:39:23

0001 /*
0002     SPDX-FileCopyrightText: 2010 Andreas Pakulat <apaku@gmx.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "projectmodelperformancetest.h"
0008 
0009 #include <QApplication>
0010 #include <QDebug>
0011 #include <QElapsedTimer>
0012 #include <QGridLayout>
0013 #include <QPushButton>
0014 #include <QTimer>
0015 #include <QTreeView>
0016 
0017 #include <projectmodel.h>
0018 #include <path.h>
0019 #include <tests/testcore.h>
0020 #include <tests/autotestshell.h>
0021 #include <tests/testplugincontroller.h>
0022 
0023 // Knobs to increase/decrease the amount of items being generated
0024 #define SMALL_DEPTH 2
0025 #define SMALL_WIDTH 10
0026 #define BIG_DEPTH 3
0027 #define BIG_WIDTH 10
0028 #define INIT_WIDTH 10
0029 #define INIT_DEPTH 3
0030 
0031 using KDevelop::ProjectModel;
0032 using KDevelop::ProjectFolderItem;
0033 using KDevelop::ProjectBaseItem;
0034 using KDevelop::ProjectFileItem;
0035 using KDevelop::Path;
0036 
0037 void generateChilds( ProjectBaseItem* parent, int count, int depth )
0038 {
0039     for( int i = 0; i < 10; i++ ) {
0040         if( depth > 0 ) {
0041             auto* item = new ProjectFolderItem( QStringLiteral( "f%1" ).arg( i ), parent );
0042             generateChilds( item, count, depth - 1 );
0043         } else {
0044             new ProjectFileItem( QStringLiteral( "f%1" ).arg( i ), parent );
0045         }
0046     }
0047 }
0048 
0049 ProjectModelPerformanceTest::ProjectModelPerformanceTest(QWidget* parent )
0050     : QWidget(parent)
0051 {
0052     auto * l = new QGridLayout( this );
0053     setLayout( l );
0054     view = new QTreeView( this );
0055     // This is used so the treeview layout performance is not influencing the test
0056     view->setUniformRowHeights( true );
0057 
0058     auto* b = new QPushButton(QStringLiteral("Expand All"), this);
0059     connect( b, &QPushButton::clicked, view, &QTreeView::expandAll );
0060     l->addWidget( b, 0, 0 );
0061     b = new QPushButton( QStringLiteral("Collapse All"), this );
0062     connect( b, &QPushButton::clicked, view, &QTreeView::collapseAll );
0063     l->addWidget( b, 0, 1 );
0064     b = new QPushButton( QStringLiteral("Add Small Subtree"), this );
0065     connect( b, &QPushButton::clicked, this, &ProjectModelPerformanceTest::addSmallTree );
0066     l->addWidget( b, 0, 2 );
0067     b = new QPushButton( QStringLiteral("Add Big Subtree"), this );
0068     connect( b, &QPushButton::clicked, this, &ProjectModelPerformanceTest::addBigTree );
0069     l->addWidget( b, 0, 3 );
0070     b = new QPushButton( QStringLiteral("Add Big Subtree in Chunks"), this );
0071     connect( b, &QPushButton::clicked, this, &ProjectModelPerformanceTest::addBigTreeDelayed );
0072     l->addWidget( b, 0, 4 );
0073 
0074     l->addWidget( view, 1, 0, 1, 6 );
0075 }
0076 
0077 void ProjectModelPerformanceTest::init()
0078 {
0079     QElapsedTimer timer;
0080     timer.start();
0081     KDevelop::AutoTestShell::init();
0082     auto* core = new KDevelop::TestCore;
0083     core->setPluginController(new KDevelop::TestPluginController(core));
0084     core->initialize();
0085 
0086     qDebug() << "init core" << timer.elapsed();
0087     timer.start();
0088 
0089     model = new KDevelop::ProjectModel( this );
0090 
0091     qDebug() << "create model" << timer.elapsed();
0092     timer.start();
0093 
0094     for( int i = 0; i < INIT_WIDTH; i++ ) {
0095         auto* item = new ProjectFolderItem( nullptr, Path( QUrl::fromLocalFile( QStringLiteral( "/f%1" ).arg( i ) ) ) );
0096         generateChilds( item, INIT_WIDTH, INIT_DEPTH );
0097         model->appendRow( item );
0098     }
0099 
0100     qDebug() << "init model" << timer.elapsed();
0101     timer.start();
0102 
0103     view->setModel( model );
0104     qDebug() << "set model" << timer.elapsed();
0105     timer.start();
0106 
0107 }
0108 
0109 ProjectModelPerformanceTest::~ProjectModelPerformanceTest()
0110 {
0111     KDevelop::TestCore::shutdown();
0112     QApplication::quit();
0113 }
0114 
0115 void ProjectModelPerformanceTest::addBigTree()
0116 {
0117     QElapsedTimer timer;
0118     timer.start();
0119     for( int i = 0; i < BIG_WIDTH; i++ ) {
0120         auto* item = new ProjectFolderItem( nullptr, Path( QUrl::fromLocalFile( QStringLiteral( "/f%1" ).arg( i ) ) ) );
0121         generateChilds( item, BIG_WIDTH, BIG_DEPTH );
0122         model->appendRow( item );
0123     }
0124     qDebug() << "addBigTree" << timer.elapsed();
0125 }
0126 
0127 void ProjectModelPerformanceTest::addBigTreeDelayed()
0128 {
0129     originalWidth = model->rowCount();
0130     QTimer::singleShot( 0, this, &ProjectModelPerformanceTest::addItemDelayed );
0131 }
0132 
0133 void ProjectModelPerformanceTest::addItemDelayed()
0134 {
0135     QElapsedTimer timer;
0136     timer.start();
0137     ProjectBaseItem* parent = nullptr;
0138     Path path;
0139     if( !currentParent.isEmpty() ) {
0140         parent = currentParent.top();
0141         path = Path(parent->path(), QStringLiteral("f%1").arg(parent->rowCount()));
0142     } else {
0143         path = Path(QUrl::fromLocalFile(QStringLiteral("/f%1").arg(model->rowCount())));
0144     }
0145     ProjectBaseItem* item = nullptr;
0146     if( currentParent.size() < BIG_DEPTH ) {
0147         item = new ProjectFolderItem(nullptr, path, parent);
0148     } else {
0149         item = new ProjectFileItem( nullptr, path, parent );
0150     }
0151     if( currentParent.isEmpty() ) {
0152         model->appendRow( item );
0153     }
0154 
0155     // Abort/Continue conditions are:
0156     // Go one level deeper (by pushing item on stack) as long as we haven't reached the max depth or the max width
0157     // else if we've reached the max width then pop, i.e go one level up
0158     // else the next run will add a sibling to the just-generated item
0159     if( currentParent.size() < BIG_DEPTH && ( currentParent.isEmpty() || currentParent.top()->rowCount() < BIG_WIDTH ) ) {
0160         currentParent.push( item );
0161     } else if( !currentParent.isEmpty() && currentParent.top()->rowCount() >= BIG_WIDTH ) {
0162         currentParent.pop();
0163     }
0164     if( ( currentParent.isEmpty() && ( model->rowCount() - originalWidth ) < BIG_WIDTH ) || !currentParent.isEmpty() ) {
0165         QTimer::singleShot( 0, this, &ProjectModelPerformanceTest::addItemDelayed );
0166     }
0167     qDebug() << "addBigTreeDelayed" << timer.elapsed();
0168 }
0169 
0170 void ProjectModelPerformanceTest::addSmallTree()
0171 {
0172     QElapsedTimer timer;
0173     timer.start();
0174     for( int i = 0; i < SMALL_WIDTH; i++ ) {
0175         auto* item = new ProjectFolderItem( nullptr, Path(QUrl::fromLocalFile( QStringLiteral( "/f%1" ).arg( i ) )) );
0176         generateChilds( item, SMALL_WIDTH, SMALL_DEPTH );
0177         model->appendRow( item );
0178     }
0179     qDebug() << "addSmallTree" << timer.elapsed();
0180 }
0181 
0182 int main( int argc, char** argv )
0183 {
0184     QApplication a( argc, argv );
0185     auto* w = new ProjectModelPerformanceTest;
0186     w->show();
0187     w->setAttribute(Qt::WA_DeleteOnClose);
0188 
0189     QMetaObject::invokeMethod(w, "init");
0190     return a.exec();
0191 }
0192 
0193 #include "moc_projectmodelperformancetest.cpp"