Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_chunk_allocator.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 "kis_debug.h"
9
10
11#define GAP_SIZE(low, high) ((high) - (low) > 0 ? (high) - (low) - 1 : 0)
12
13#define HAS_NEXT(list,iter) ((iter)!=(list).end())
14#define HAS_PREVIOUS(list,iter) ((iter)!=(list).begin())
15
16#define PEEK_NEXT(iter) (*(iter))
17#define PEEK_PREVIOUS(iter) (*((iter)-1))
18#define WRAP_PREVIOUS_CHUNK_DATA(iter) (KisChunk((iter)-1))
19
20
21KisChunkAllocator::KisChunkAllocator(quint64 slabSize, quint64 storeSize)
22{
23 m_storeMaxSize = storeSize;
24 m_storeSlabSize = slabSize;
25
26 m_iterator = m_list.begin();
29}
30
34
36{
39
40 forever {
43
44 if(m_iterator == m_list.end())
45 break;
46
47 m_iterator++;
49 }
50
52 m_iterator = m_list.begin();
53
54 forever {
57
58 if(m_iterator == m_list.end() || m_iterator == startPosition)
59 break;
60
61 m_iterator++;
63 }
64
66 m_iterator = m_list.end();
67
71 }
72
73 qFatal("KisChunkAllocator: out of swap space");
74
75 // just let gcc be happy! :)
76 return KisChunk(m_list.end());
77}
78
81 quint64 size)
82{
83 bool result = false;
84 quint64 highBound = m_storeSize;
85 quint64 lowBound = 0;
86 quint64 shift = 0;
87
88 if(HAS_NEXT(list, iterator))
89 highBound = PEEK_NEXT(iterator).m_begin;
90
91 if(HAS_PREVIOUS(list, iterator)) {
92 lowBound = PEEK_PREVIOUS(iterator).m_end;
93 shift = 1;
94 }
95
96 if(GAP_SIZE(lowBound, highBound) >= size) {
97 list.insert(iterator, KisChunkData(lowBound + shift, size));
98 result = true;
99 }
100
101 return result;
102}
103
105{
106 if(m_iterator != m_list.end() && m_iterator == chunk.position()) {
108 return;
109 }
110
111 Q_ASSERT(chunk.position()->m_begin == chunk.begin());
112 m_list.erase(chunk.position());
113}
114
115
116
117/**************************************************************/
118/******* Debugging features ********/
119/**************************************************************/
120
121
123{
124 quint64 idx = 0;
126
127 for(i = m_list.begin(); i != m_list.end(); ++i) {
128 qInfo("chunk #%lld: [%lld %lld]", idx++, i->m_begin, i->m_end);
129 }
130}
131
132bool KisChunkAllocator::sanityCheck(bool pleaseCrash)
133{
134 bool failed = false;
136
137 for(i = m_list.begin(); i != m_list.end(); ++i) {
138 if(HAS_PREVIOUS(m_list, i)) {
139 if(PEEK_PREVIOUS(i).m_end >= i->m_begin) {
140 qWarning("Chunks overlapped: [%lld %lld], [%lld %lld]", PEEK_PREVIOUS(i).m_begin, PEEK_PREVIOUS(i).m_end, i->m_begin, i->m_end);
141 failed = true;
142 break;
143 }
144 }
145 }
146
147 i = m_list.end();
148 if(HAS_PREVIOUS(m_list, i)) {
149 if(PEEK_PREVIOUS(i).m_end >= m_storeSize) {
150 warnKrita << "Last chunk exceeds the store size!";
151 failed = true;
152 }
153 }
154
155 if(failed && pleaseCrash)
156 qFatal("KisChunkAllocator: sanity check failed!");
157
158 return !failed;
159}
160
162{
164
165 quint64 totalSize = 0;
166 quint64 allocated = 0;
167 quint64 free = 0;
168 qreal fragmentation = 0;
169
170 for(i = m_list.begin(); i != m_list.end(); ++i) {
171 allocated += i->m_end - i->m_begin + 1;
172
173 if(HAS_PREVIOUS(m_list, i))
174 free += GAP_SIZE(PEEK_PREVIOUS(i).m_end, i->m_begin);
175 else
176 free += i->m_begin;
177 }
178
179 i = m_list.end();
180 if(HAS_PREVIOUS(m_list, i))
181 totalSize = PEEK_PREVIOUS(i).m_end + 1;
182
183 if(totalSize)
184 fragmentation = qreal(free) / totalSize;
185
186 if(toStderr) {
187 qInfo() << "Hard store limit:\t" << m_storeMaxSize;
188 qInfo() << "Slab size:\t\t" << m_storeSlabSize;
189 qInfo() << "Num slabs:\t\t" << m_storeSize / m_storeSlabSize;
190 qInfo() << "Store size:\t\t" << m_storeSize;
191 qInfo() << "Total used:\t\t" << totalSize;
192 qInfo() << "Allocated:\t\t" << allocated;
193 qInfo() << "Free:\t\t\t" << free;
194 qInfo() << "Fragmentation:\t\t" << fragmentation;
196 }
197
198 Q_ASSERT(totalSize == allocated + free);
199
200 return fragmentation;
201}
KisChunk getChunk(quint64 size)
KisChunkDataList m_list
KisChunkAllocator(quint64 slabSize=DEFAULT_SLAB_SIZE, quint64 storeSize=DEFAULT_STORE_SIZE)
qreal debugFragmentation(bool toStderr=true)
bool tryInsertChunk(KisChunkDataList &list, KisChunkDataListIterator &iterator, quint64 size)
void freeChunk(KisChunk chunk)
bool sanityCheck(bool pleaseCrash=true)
KisChunkDataListIterator m_iterator
quint64 begin() const
KisChunkDataListIterator position()
#define GAP_SIZE(low, high)
#define HAS_NEXT(list, iter)
#define HAS_PREVIOUS(list, iter)
#define PEEK_PREVIOUS(iter)
#define PEEK_NEXT(iter)
#define WRAP_PREVIOUS_CHUNK_DATA(iter)
#define REGISTER_STEP()
#define INIT_FAIL_COUNTER()
QLinkedList< KisChunkData > KisChunkDataList
#define DEBUG_FAIL_COUNTER()
#define START_COUNTING()
#define REGISTER_FAIL()
KisChunkDataList::iterator KisChunkDataListIterator
#define warnKrita
Definition kis_debug.h:87