Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tile_data_swapper.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include <QMutex>
8#include <QSemaphore>
9
15#include "kis_debug.h"
16
17#define SEC 1000
18
19const qint32 KisTileDataSwapper::TIMEOUT = -1;
20const qint32 KisTileDataSwapper::DELAY = 0.7 * SEC;
21
22//#define DEBUG_SWAPPER
23
24#ifdef DEBUG_SWAPPER
25#define DEBUG_ACTION(action) dbgKrita << action
26#define DEBUG_VALUE(value) dbgKrita << "\t" << ppVar(value)
27#else
28#define DEBUG_ACTION(action)
29#define DEBUG_VALUE(value)
30#endif
31
34
35
36struct Q_DECL_HIDDEN KisTileDataSwapper::Private
37{
38public:
39 QSemaphore semaphore;
40 QAtomicInt shouldExitFlag;
43 QMutex cycleLock;
44};
45
47 : QThread(),
48 m_d(new Private())
49{
50 m_d->shouldExitFlag = 0;
51 m_d->store = store;
52}
53
58
60{
61 m_d->semaphore.release();
62}
63
65{
66 unsigned long exitTimeout = 100;
67 do {
68 m_d->shouldExitFlag = true;
69 kick();
70 } while(!wait(exitTimeout));
71}
72
74{
75 m_d->semaphore.tryAcquire(1, TIMEOUT);
76}
77
79{
80 while (1) {
82
83 if (m_d->shouldExitFlag)
84 return;
85
86 QThread::msleep(DELAY);
87
88 doJob();
89 }
90}
91
93{
94// dbgKrita <<"check memory: high limit -" << m_d->limits.emergencyThreshold() <<"in mem -" << m_d->store->numTilesInMemory();
95 if(m_d->store->memoryMetric() > m_d->limits.emergencyThreshold())
96 doJob();
97}
98
100{
105 QMutexLocker locker(&m_d->cycleLock);
106
107 qint32 memoryMetric = m_d->store->memoryMetric();
108
109 DEBUG_ACTION("Started swap cycle");
110 DEBUG_VALUE(m_d->store->numTiles());
111 DEBUG_VALUE(m_d->store->numTilesInMemory());
112 DEBUG_VALUE(memoryMetric);
113
114 DEBUG_VALUE(m_d->limits.softLimitThreshold());
115 DEBUG_VALUE(m_d->limits.hardLimitThreshold());
116
117
118 if(memoryMetric > m_d->limits.softLimitThreshold()) {
119 qint32 softFree = memoryMetric - m_d->limits.softLimit();
120 DEBUG_VALUE(softFree);
121 DEBUG_ACTION("\t pass0");
122 memoryMetric -= pass<SoftSwapStrategy>(softFree);
123 DEBUG_VALUE(memoryMetric);
124
125 if(memoryMetric > m_d->limits.hardLimitThreshold()) {
126 qint32 hardFree = memoryMetric - m_d->limits.hardLimit();
127 DEBUG_VALUE(hardFree);
128 DEBUG_ACTION("\t pass1");
129 memoryMetric -= pass<AggressiveSwapStrategy>(hardFree);
130 DEBUG_VALUE(memoryMetric);
131 }
132 }
133}
134
135
137{
138public:
140
141 static inline iterator* beginIteration(KisTileDataStore *store) {
142 return store->beginIteration();
143 }
144
145 static inline void endIteration(KisTileDataStore *store, iterator *iter) {
146 store->endIteration(iter);
147 }
148
149 static inline bool isInteresting(KisTileData *td) {
150 // We are working with mementoed tiles only...
151 return td->historical();
152 }
153
154 static inline bool swapOutFirst(KisTileData *td) {
155 return td->age() > 0;
156 }
157};
158
160{
161public:
163
164 static inline iterator* beginIteration(KisTileDataStore *store) {
165 return store->beginClockIteration();
166 }
167
168 static inline void endIteration(KisTileDataStore *store, iterator *iter) {
169 store->endIteration(iter);
170 }
171
172 static inline bool isInteresting(KisTileData *td) {
173 // Add some aggression...
174 Q_UNUSED(td);
175 return true; // >:)
176 }
177
178 static inline bool swapOutFirst(KisTileData *td) {
179 return td->age() > 0;
180 }
181};
182
183
184template<class strategy>
185qint64 KisTileDataSwapper::pass(qint64 needToFreeMetric)
186{
187 qint64 freedMetric = 0;
188 QList<KisTileData*> additionalCandidates;
189
190 typename strategy::iterator *iter =
191 strategy::beginIteration(m_d->store);
192
193 KisTileData *item = 0;
194
195 while (iter->hasNext()) {
196 item = iter->next();
197
198 if (freedMetric >= needToFreeMetric) break;
199
200 if (!strategy::isInteresting(item)) continue;
201
202 if (strategy::swapOutFirst(item)) {
203 if (iter->trySwapOut(item)) {
204 freedMetric += item->pixelSize();
205 }
206 }
207 else {
208 item->markOld();
209 additionalCandidates.append(item);
210 }
211
212 }
213
214 Q_FOREACH (item, additionalCandidates) {
215 if (freedMetric >= needToFreeMetric) break;
216
217 if (iter->trySwapOut(item)) {
218 freedMetric += item->pixelSize();
219 }
220 }
221
222 strategy::endIteration(m_d->store, iter);
223
224 return freedMetric;
225}
226
static bool isInteresting(KisTileData *td)
static bool swapOutFirst(KisTileData *td)
KisTileDataStoreClockIterator iterator
static iterator * beginIteration(KisTileDataStore *store)
static void endIteration(KisTileDataStore *store, iterator *iter)
KisTileDataStoreClockIterator * beginClockIteration()
void endIteration(KisTileDataStoreIterator *iterator)
KisTileDataStoreIterator * beginIteration()
quint32 pixelSize() const
int age() const
bool historical() const
static bool swapOutFirst(KisTileData *td)
static iterator * beginIteration(KisTileDataStore *store)
KisTileDataStoreIterator iterator
static bool isInteresting(KisTileData *td)
static void endIteration(KisTileDataStore *store, iterator *iter)
#define DEBUG_VALUE(value)
#define SEC
#define DEBUG_ACTION(action)
qint64 pass(qint64 needToFreeMetric)
static const qint32 DELAY
static const qint32 TIMEOUT
KisTileDataSwapper(KisTileDataStore *store)