Skip to content

Commit 808ee0f

Browse files
author
Grok Compression
committed
TagTree: micro optimization
1 parent 404e1b1 commit 808ee0f

File tree

2 files changed

+141
-138
lines changed

2 files changed

+141
-138
lines changed

.vscode/launch.json

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,26 @@
485485
"MIMode": "gdb",
486486
"miDebuggerPath": "/usr/bin/gdb"
487487
},
488-
{
488+
{
489+
"name": "Excalibur Test",
490+
"type": "cppdbg",
491+
"request": "launch",
492+
"program": "/usr/bin/time",
493+
"args": [
494+
"-v",
495+
"${workspaceFolder}/build/bin/core_decompress",
496+
"-i",
497+
"$HOME/temp/2048x2048.jp2",
498+
],
499+
"cwd": "${workspaceFolder}",
500+
"environment": [
501+
{ "name": "GRK_DEBUG", "value": "3" },
502+
{ "name": "GRK_EXCALIBUR", "value": "1" }
503+
],
504+
"MIMode": "gdb",
505+
"miDebuggerPath": "/usr/bin/gdb"
506+
},
507+
{
489508
"name": "Pleiades",
490509
"type": "cppdbg",
491510
"request": "launch",

src/lib/core/t2/TagTree.h

Lines changed: 121 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -20,112 +20,26 @@
2020
#include <limits>
2121
#include <stdexcept>
2222
#include <iostream>
23+
#include <vector>
24+
2325

2426
namespace grk
2527
{
2628

27-
/**
28-
Tag node
29-
*/
30-
template<typename T>
31-
struct TagTreeNode
32-
{
33-
TagTreeNode() : parent(nullptr), value(0), low(0), known(false) {}
34-
35-
TagTreeNode* parent;
36-
T value;
37-
T low;
38-
bool known;
39-
};
40-
41-
/**
42-
Tag tree
43-
*/
4429
template<typename T>
4530
class TagTree
4631
{
4732
public:
48-
/**
49-
* @brief TagTree constructor
50-
*
51-
* @param leavesWidth Width of the array of leaves of the tree
52-
* @param leavesHeight Height of the array of leaves of the tree
53-
*
54-
* @return a new tag tree if successful, otherwise nullptr
55-
*/
5633
TagTree(uint16_t leavesWidth, uint16_t leavesHeight)
57-
: leavesWidth_(leavesWidth), leavesHeight_(leavesHeight), nodeCount(0), nodes(nullptr)
34+
: leavesWidth_(leavesWidth), leavesHeight_(leavesHeight)
5835
{
59-
uint16_t resLeavesWidth[16];
60-
uint16_t resLeavesHeight[16];
61-
int8_t numLevels = 0;
62-
resLeavesWidth[0] = leavesWidth_;
63-
resLeavesHeight[0] = leavesHeight_;
64-
nodeCount = 0;
65-
uint32_t nodesPerLevel;
66-
67-
do
68-
{
69-
if(numLevels == 16)
70-
{
71-
grklog.error("TagTree constructor: num level overflow");
72-
throw std::runtime_error("TagTree constructor: num level overflow");
73-
}
74-
nodesPerLevel = static_cast<uint32_t>(resLeavesWidth[numLevels]) * resLeavesHeight[numLevels];
75-
resLeavesWidth[numLevels + 1] = (uint16_t)((resLeavesWidth[numLevels] + 1) >> 1);
76-
resLeavesHeight[numLevels + 1] = (uint16_t)((resLeavesHeight[numLevels] + 1) >> 1);
77-
nodeCount += nodesPerLevel;
78-
++numLevels;
79-
} while(nodesPerLevel > 1);
80-
81-
if(nodeCount == 0)
82-
{
83-
grklog.warn("tgt_create numnodes == 0, no tree created.");
84-
throw std::runtime_error("tgt_create numnodes == 0, no tree created");
85-
}
86-
87-
nodes = new TagTreeNode<T>[nodeCount];
88-
auto currentNode = nodes;
89-
auto parentNode = nodes + static_cast<uint32_t>(leavesWidth_) * leavesHeight_;
90-
auto parentNodeNext = parentNode;
91-
92-
for(int8_t i = 0; i < numLevels - 1; ++i)
93-
{
94-
for(uint16_t j = 0U; j < resLeavesHeight[i]; ++j)
95-
{
96-
int64_t k = resLeavesWidth[i];
97-
while(--k >= 0)
98-
{
99-
currentNode->parent = parentNode;
100-
++currentNode;
101-
if(--k >= 0)
102-
{
103-
currentNode->parent = parentNode;
104-
++currentNode;
105-
}
106-
++parentNode;
107-
}
108-
if((j & 1) || j == resLeavesHeight[i] - 1)
109-
{
110-
parentNodeNext = parentNode;
111-
}
112-
else
113-
{
114-
parentNode = parentNodeNext;
115-
parentNodeNext += resLeavesWidth[i];
116-
}
117-
}
118-
}
119-
currentNode->parent = nullptr;
36+
buildTree();
12037
reset();
12138
}
12239

123-
~TagTree()
124-
{
125-
delete[] nodes;
126-
}
40+
~TagTree() = default;
12741

128-
constexpr T getUninitializedValue(void)
42+
constexpr T getUninitializedValue() const noexcept
12943
{
13044
return (std::numeric_limits<T>::max)();
13145
}
@@ -135,13 +49,14 @@ class TagTree
13549
*/
13650
void reset()
13751
{
138-
for(auto i = 0U; i < nodeCount; ++i)
52+
for(auto& n : nodes_)
13953
{
140-
auto current_node = nodes + i;
141-
current_node->value = getUninitializedValue();
142-
current_node->low = 0;
143-
current_node->known = false;
54+
n.value = getUninitializedValue();
55+
n.low = 0;
56+
n.known = false;
14457
}
58+
for(auto& v : leafCache_)
59+
v = getUninitializedValue();
14560
}
14661

14762
/**
@@ -151,11 +66,11 @@ class TagTree
15166
*/
15267
void set(uint64_t leafno, T value)
15368
{
154-
auto node = nodes + leafno;
155-
while(node && node->value > value)
69+
uint32_t node = static_cast<uint32_t>(leafno);
70+
while(node != UINT32_MAX && nodes_[node].value > value)
15671
{
157-
node->value = value;
158-
node = node->parent;
72+
nodes_[node].value = value;
73+
node = parents_[node];
15974
}
16075
}
16176

@@ -168,42 +83,44 @@ class TagTree
16883
*/
16984
bool encode(t1_t2::BitIO* bio, uint64_t leafno, T threshold)
17085
{
171-
TagTreeNode<T>* nodeStack[15];
172-
auto nodeStackPtr = nodeStack;
173-
auto node = nodes + leafno;
174-
while(node->parent)
86+
// exact original encode logic, using flat indices
87+
uint32_t nodeStack[16];
88+
int stackPtr = 0;
89+
uint32_t node = static_cast<uint32_t>(leafno);
90+
while(parents_[node] != UINT32_MAX)
17591
{
176-
*nodeStackPtr++ = node;
177-
node = node->parent;
92+
nodeStack[stackPtr++] = node;
93+
node = parents_[node];
17894
}
17995
T low = 0;
18096
while(true)
18197
{
182-
if(node->low < low)
183-
node->low = low;
98+
auto& n = nodes_[node];
99+
if(n.low < low)
100+
n.low = low;
184101
else
185-
low = node->low;
102+
low = n.low;
186103

187104
while(low < threshold)
188105
{
189-
if(low >= node->value)
106+
if(low >= n.value)
190107
{
191-
if(!node->known)
108+
if(!n.known)
192109
{
193110
if(!bio->write(1))
194111
return false;
195-
node->known = true;
112+
n.known = true;
196113
}
197114
break;
198115
}
199116
if(!bio->write(0))
200117
return false;
201118
++low;
202119
}
203-
node->low = low;
204-
if(nodeStackPtr == nodeStack)
120+
n.low = low;
121+
if(stackPtr == 0)
205122
break;
206-
node = *--nodeStackPtr;
123+
node = nodeStack[--stackPtr];
207124
}
208125
return true;
209126
}
@@ -217,49 +134,116 @@ class TagTree
217134
*/
218135
void decode(t1_t2::BitIO* bio, uint64_t leafno, T threshold, T* value)
219136
{
220-
TagTreeNode<T>* nodeStack[15];
137+
if(leafCache_[leafno] < threshold) [[likely]]
138+
{
139+
*value = leafCache_[leafno];
140+
return;
141+
}
142+
221143
*value = getUninitializedValue();
222-
auto nodeStackPtr = nodeStack;
223-
auto node = nodes + leafno;
224-
// climb to top of tree
225-
while(node->parent)
144+
145+
uint32_t nodeStack[16];
146+
int stackPtr = 0;
147+
uint32_t node = static_cast<uint32_t>(leafno);
148+
149+
// climb to root (exact same path as encode)
150+
while(parents_[node] != UINT32_MAX)
226151
{
227-
*nodeStackPtr++ = node;
228-
node = node->parent;
152+
nodeStack[stackPtr++] = node;
153+
node = parents_[node];
229154
}
230-
// descend to bottom of tree
155+
231156
T low = 0;
232157
while(true)
233158
{
234-
if(node->low < low)
235-
node->low = low;
159+
auto& n = nodes_[node];
160+
161+
if(n.low < low)
162+
n.low = low;
236163
else
237-
low = node->low;
238-
while(low < threshold && low < node->value)
164+
low = n.low;
165+
166+
while(low < threshold && low < n.value) [[likely]]
239167
{
240168
if(bio->read())
241169
{
242-
node->value = low;
170+
n.value = low;
243171
break;
244172
}
245-
low++;
173+
++low;
246174
}
247-
node->low = low;
248-
if(nodeStackPtr == nodeStack)
175+
n.low = low;
176+
177+
if(stackPtr == 0) [[unlikely]]
249178
break;
250-
node = *--nodeStackPtr;
179+
180+
node = nodeStack[--stackPtr]; // descend to child
251181
}
252-
*value = node->value;
182+
183+
*value = nodes_[node].value; // now guaranteed to be the leaf node
184+
if(*value < threshold)
185+
leafCache_[leafno] = *value;
253186
}
254187

255188
private:
189+
struct Node
190+
{
191+
T value;
192+
T low;
193+
bool known;
194+
};
195+
196+
void buildTree()
197+
{
198+
// same level calculation as original
199+
uint16_t resW[16]{}, resH[16]{};
200+
int8_t levels = 0;
201+
resW[0] = leavesWidth_;
202+
resH[0] = leavesHeight_;
203+
uint64_t totalNodes = 0;
204+
uint32_t nodesPerLevel;
205+
206+
do
207+
{
208+
nodesPerLevel = static_cast<uint32_t>(resW[levels]) * resH[levels];
209+
resW[levels + 1] = (uint16_t)((resW[levels] + 1) >> 1);
210+
resH[levels + 1] = (uint16_t)((resH[levels] + 1) >> 1);
211+
totalNodes += nodesPerLevel;
212+
++levels;
213+
} while(nodesPerLevel > 1);
214+
215+
nodes_.resize(totalNodes);
216+
parents_.resize(totalNodes, UINT32_MAX);
217+
leafCache_.resize(static_cast<uint64_t>(leavesWidth_) * leavesHeight_);
218+
219+
// build parents (exact same linking logic as original, but with indices)
220+
uint64_t parentBase = static_cast<uint64_t>(leavesWidth_) * leavesHeight_;
221+
uint64_t cur = 0;
222+
223+
for(int8_t lvl = 0; lvl < levels - 1; ++lvl)
224+
{
225+
uint32_t w = resW[lvl];
226+
uint32_t h = resH[lvl];
227+
for(uint32_t j = 0; j < h; ++j)
228+
{
229+
for(uint32_t k = 0; k < w; ++k)
230+
{
231+
parents_[cur] = static_cast<uint32_t>(parentBase + (j >> 1) * resW[lvl + 1] + (k >> 1));
232+
++cur;
233+
}
234+
}
235+
parentBase += static_cast<uint64_t>(resW[lvl + 1]) * resH[lvl + 1];
236+
}
237+
}
238+
256239
uint16_t leavesWidth_;
257240
uint16_t leavesHeight_;
258-
uint64_t nodeCount;
259-
TagTreeNode<T>* nodes;
241+
std::vector<Node> nodes_;
242+
std::vector<uint32_t> parents_; // UINT32_MAX = root
243+
std::vector<T> leafCache_;
260244
};
261245

262246
using TagTreeU8 = TagTree<uint8_t>;
263247
using TagTreeU16 = TagTree<uint16_t>;
264248

265-
} // namespace grk
249+
} // namespace grk

0 commit comments

Comments
 (0)