File indexing completed on 2024-12-22 04:10:27
0001 /* 0002 * SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_updater_context_test.h" 0008 #include <simpletest.h> 0009 0010 #include "kistest.h" 0011 0012 #include <QAtomicInt> 0013 #include <KoColorSpace.h> 0014 #include <KoColorSpaceRegistry.h> 0015 0016 #include "kis_paint_layer.h" 0017 0018 #include "kis_merge_walker.h" 0019 #include "kis_updater_context.h" 0020 #include "kis_image.h" 0021 0022 #include "scheduler_utils.h" 0023 0024 #include "lod_override.h" 0025 #include "config-limit-long-tests.h" 0026 0027 void KisUpdaterContextTest::testJobInterference() 0028 { 0029 KisTestableUpdaterContext context(3); 0030 0031 QRect imageRect(0,0,100,100); 0032 0033 const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); 0034 KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), cs, "merge test"); 0035 0036 KisPaintLayerSP paintLayer = new KisPaintLayer(image, "test", OPACITY_OPAQUE_U8); 0037 0038 image->barrierLock(); 0039 image->addNode(paintLayer); 0040 image->unlock(); 0041 0042 QRect dirtyRect1(0,0,50,100); 0043 KisBaseRectsWalkerSP walker1 = new KisMergeWalker(imageRect); 0044 walker1->collectRects(paintLayer, dirtyRect1); 0045 0046 context.lock(); 0047 context.addMergeJob(walker1); 0048 context.unlock(); 0049 0050 // overlapping job --- forbidden 0051 { 0052 QRect dirtyRect(30,0,100,100); 0053 KisBaseRectsWalkerSP walker = new KisMergeWalker(imageRect); 0054 walker->collectRects(paintLayer, dirtyRect); 0055 0056 context.lock(); 0057 QVERIFY(!context.isJobAllowed(walker)); 0058 context.unlock(); 0059 } 0060 0061 // not overlapping job --- allowed 0062 { 0063 QRect dirtyRect(60,0,100,100); 0064 KisBaseRectsWalkerSP walker = new KisMergeWalker(imageRect); 0065 walker->collectRects(paintLayer, dirtyRect); 0066 0067 context.lock(); 0068 QVERIFY(context.isJobAllowed(walker)); 0069 context.unlock(); 0070 } 0071 0072 // not overlapping job, conflicting LOD --- forbidden 0073 { 0074 TestUtil::LodOverride l(1, image); 0075 0076 QCOMPARE(paintLayer->paintDevice()->defaultBounds()->currentLevelOfDetail(), 1); 0077 0078 QRect dirtyRect(60,0,100,100); 0079 KisBaseRectsWalkerSP walker = new KisMergeWalker(imageRect); 0080 walker->collectRects(paintLayer, dirtyRect); 0081 0082 context.lock(); 0083 QVERIFY(!context.isJobAllowed(walker)); 0084 context.unlock(); 0085 } 0086 } 0087 0088 void KisUpdaterContextTest::testSnapshot() 0089 { 0090 KisTestableUpdaterContext context(3); 0091 0092 QRect imageRect(0,0,100,100); 0093 0094 KisBaseRectsWalkerSP walker1 = new KisMergeWalker(imageRect); 0095 0096 qint32 numMergeJobs = -777; 0097 qint32 numStrokeJobs = -777; 0098 0099 context.lock(); 0100 0101 context.getJobsSnapshot(numMergeJobs, numStrokeJobs); 0102 QCOMPARE(numMergeJobs, 0); 0103 QCOMPARE(numStrokeJobs, 0); 0104 QCOMPARE(context.currentLevelOfDetail(), -1); 0105 0106 context.addMergeJob(walker1); 0107 context.getJobsSnapshot(numMergeJobs, numStrokeJobs); 0108 QCOMPARE(numMergeJobs, 1); 0109 QCOMPARE(numStrokeJobs, 0); 0110 QCOMPARE(context.currentLevelOfDetail(), 0); 0111 0112 0113 KisStrokeJobData *data = 0114 new KisStrokeJobData(KisStrokeJobData::SEQUENTIAL, 0115 KisStrokeJobData::NORMAL); 0116 0117 QScopedPointer<KisStrokeJobStrategy> strategy( 0118 new KisNoopDabStrategy("test")); 0119 0120 context.addStrokeJob(new KisStrokeJob(strategy.data(), data, 0, true)); 0121 context.getJobsSnapshot(numMergeJobs, numStrokeJobs); 0122 QCOMPARE(numMergeJobs, 1); 0123 QCOMPARE(numStrokeJobs, 1); 0124 QCOMPARE(context.currentLevelOfDetail(), 0); 0125 0126 0127 context.addSpontaneousJob(new KisNoopSpontaneousJob()); 0128 context.getJobsSnapshot(numMergeJobs, numStrokeJobs); 0129 QCOMPARE(numMergeJobs, 2); 0130 QCOMPARE(numStrokeJobs, 1); 0131 QCOMPARE(context.currentLevelOfDetail(), 0); 0132 0133 context.unlock(); 0134 0135 { 0136 context.lock(); 0137 context.clear(); 0138 0139 context.getJobsSnapshot(numMergeJobs, numStrokeJobs); 0140 QCOMPARE(numMergeJobs, 0); 0141 QCOMPARE(numStrokeJobs, 0); 0142 QCOMPARE(context.currentLevelOfDetail(), -1); 0143 0144 data = 0145 new KisStrokeJobData(KisStrokeJobData::SEQUENTIAL, 0146 KisStrokeJobData::NORMAL); 0147 0148 context.addStrokeJob(new KisStrokeJob(strategy.data(), data, 2, true)); 0149 context.getJobsSnapshot(numMergeJobs, numStrokeJobs); 0150 QCOMPARE(numMergeJobs, 0); 0151 QCOMPARE(numStrokeJobs, 1); 0152 QCOMPARE(context.currentLevelOfDetail(), 2); 0153 0154 context.unlock(); 0155 } 0156 } 0157 0158 #define NUM_THREADS 10 0159 #ifdef LIMIT_LONG_TESTS 0160 # define NUM_JOBS 60 0161 #else 0162 # define NUM_JOBS 6000 0163 #endif 0164 #define EXCLUSIVE_NTH 3 0165 #define NUM_CHECKS 10 0166 #define CHECK_DELAY 3 // ms 0167 0168 class ExclusivenessCheckerStrategy : public KisStrokeJobStrategy 0169 { 0170 public: 0171 ExclusivenessCheckerStrategy(QAtomicInt &counter, 0172 QAtomicInt &hadConcurrency) 0173 : m_counter(counter), 0174 m_hadConcurrency(hadConcurrency) 0175 { 0176 } 0177 0178 void run(KisStrokeJobData *data) override { 0179 Q_UNUSED(data); 0180 0181 m_counter.ref(); 0182 0183 for(int i = 0; i < NUM_CHECKS; i++) { 0184 if(data->isExclusive()) { 0185 Q_ASSERT(m_counter == 1); 0186 } 0187 else if (m_counter > 1) { 0188 m_hadConcurrency.ref(); 0189 } 0190 QTest::qSleep(CHECK_DELAY); 0191 } 0192 0193 m_counter.deref(); 0194 } 0195 0196 QString debugId() const override { 0197 return "ExclusivenessCheckerStrategy"; 0198 } 0199 0200 private: 0201 QAtomicInt &m_counter; 0202 QAtomicInt &m_hadConcurrency; 0203 }; 0204 0205 void KisUpdaterContextTest::stressTestExclusiveJobs() 0206 { 0207 KisUpdaterContext context(NUM_THREADS); 0208 QAtomicInt counter; 0209 QAtomicInt hadConcurrency; 0210 0211 for(int i = 0; i < NUM_JOBS; i++) { 0212 if(context.hasSpareThread()) { 0213 bool isExclusive = i % EXCLUSIVE_NTH == 0; 0214 0215 KisStrokeJobData *data = 0216 new KisStrokeJobData(KisStrokeJobData::SEQUENTIAL, 0217 isExclusive ? 0218 KisStrokeJobData::EXCLUSIVE : 0219 KisStrokeJobData::NORMAL); 0220 0221 KisStrokeJobStrategy *strategy = 0222 new ExclusivenessCheckerStrategy(counter, hadConcurrency); 0223 0224 context.addStrokeJob(new KisStrokeJob(strategy, data, 0, true)); 0225 } 0226 else { 0227 QTest::qSleep(CHECK_DELAY); 0228 } 0229 } 0230 0231 context.waitForDone(); 0232 0233 QVERIFY(!counter); 0234 dbgKrita << "Concurrency observed:" << hadConcurrency 0235 << "/" << NUM_CHECKS * NUM_JOBS; 0236 } 0237 0238 KISTEST_MAIN(KisUpdaterContextTest) 0239