CoDiPack  2.2.0
A Code Differentiation Package
SciComp TU Kaiserslautern
Loading...
Searching...
No Matches
chunkedData.hpp
1/*
2 * CoDiPack, a Code Differentiation Package
3 *
4 * Copyright (C) 2015-2024 Chair for Scientific Computing (SciComp), University of Kaiserslautern-Landau
5 * Homepage: http://www.scicomp.uni-kl.de
6 * Contact: Prof. Nicolas R. Gauger (codi@scicomp.uni-kl.de)
7 *
8 * Lead developers: Max Sagebaum, Johannes Blühdorn (SciComp, University of Kaiserslautern-Landau)
9 *
10 * This file is part of CoDiPack (http://www.scicomp.uni-kl.de/software/codi).
11 *
12 * CoDiPack is free software: you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, either version 3 of the
15 * License, or (at your option) any later version.
16 *
17 * CoDiPack is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty
19 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * See the GNU General Public License for more details.
22 * You should have received a copy of the GNU
23 * General Public License along with CoDiPack.
24 * If not, see <http://www.gnu.org/licenses/>.
25 *
26 * For other licensing options please contact us.
27 *
28 * Authors:
29 * - SciComp, University of Kaiserslautern-Landau:
30 * - Max Sagebaum
31 * - Johannes Blühdorn
32 * - Former members:
33 * - Tim Albring
34 */
35#pragma once
36
37#include <vector>
38
39#include "../../config.h"
40#include "../../misc/macros.hpp"
41#include "../../traits/misc/enableIfHelpers.hpp"
42#include "chunk.hpp"
43#include "dataInterface.hpp"
44#include "emptyData.hpp"
45#include "pointerStore.hpp"
46#include "position.hpp"
47
49namespace codi {
50
63 template<typename T_Chunk, typename T_NestedData = EmptyData, typename T_PointerInserter = PointerStore<T_Chunk>>
64 struct ChunkedData : public DataInterface<T_NestedData> {
65 public:
66
67 using Chunk = CODI_DD(T_Chunk, Chunk1<CODI_ANY>);
69 using PointerInserter = CODI_DD(T_PointerInserter, CODI_T(PointerStore<Chunk>));
70
71 using InternalPosHandle = size_t;
72 using NestedPosition = typename NestedData::Position;
73
75 template<int selectedDepth>
77 typename std::conditional<selectedDepth == 0, TerminatingPointerStore<PointerInserter>,
78 PointerInserter>::type;
79
81
82 private:
83 std::vector<Chunk*> chunks;
84 std::vector<NestedPosition> positions;
85
86 Chunk* curChunk;
87 size_t curChunkIndex;
88
89 size_t chunkSize;
90
91 NestedData* nested;
92
93 public:
94
96 ChunkedData(size_t const& chunkSize, NestedData* nested)
97 : chunks(), positions(), curChunk(nullptr), curChunkIndex(0), chunkSize(chunkSize), nested(nullptr) {
98 setNested(nested);
99 }
100
102 ChunkedData(size_t const& chunkSize)
103 : chunks(), positions(), curChunk(nullptr), curChunkIndex(0), chunkSize(chunkSize), nested(nullptr) {}
104
107 for (size_t i = 0; i < chunks.size(); ++i) {
108 delete chunks[i];
109 }
110 }
111
112 /*******************************************************************************/
114
116 template<typename... Data>
117 CODI_INLINE void pushData(Data const&... data) {
118 // This method should only be called if reserveItems has been called.
119 curChunk->pushData(data...);
120 }
121
123 template<typename... Data>
124 CODI_INLINE void getDataPointers(Data*&... pointers) {
125 // This method should only be called if reserveItems has been called.
126 curChunk->dataPointer(curChunk->getUsedSize(), pointers...);
127 }
128
130 CODI_INLINE void addDataSize(size_t size) {
131 // This method should only be called if reserveItems has been called.
132 curChunk->setUsedSize(curChunk->getUsedSize() + size);
133 }
134
138 codiAssert(items <= chunkSize);
139
140 if (chunkSize < curChunk->getUsedSize() + items) {
141 nextChunk();
142 }
143
144 return curChunk->getUsedSize();
145 }
146
147 /*******************************************************************************/
149
151 void resize(size_t const& totalSize) {
152 size_t noOfChunks = totalSize / chunkSize;
153 if (0 != totalSize % chunkSize) {
154 noOfChunks += 1;
155 }
156
157 for (size_t i = chunks.size(); i < noOfChunks; ++i) {
158 chunks.push_back(new Chunk(chunkSize));
159 positions.push_back(nested->getPosition());
160 }
161 }
162
164 void reset() {
166 }
167
169 void resetHard() {
170 for (size_t i = 1; i < chunks.size(); ++i) {
171 delete chunks[i];
172 }
173
174 chunks.resize(1);
175 positions.resize(1);
176 curChunk = chunks[0];
177
178 curChunk->setUsedSize(0);
179 curChunkIndex = 0;
180
181 nested->resetHard();
182 }
183
185 void resetTo(Position const& pos) {
186 codiAssert(pos.chunk < chunks.size());
187 codiAssert(pos.data <= chunkSize);
188
189 for (size_t i = pos.chunk + 1; i <= curChunkIndex; i += 1) {
190 chunks[i]->reset();
191 }
192
193 curChunk = chunks[pos.chunk];
194 curChunk->setUsedSize(pos.data);
195 curChunkIndex = pos.chunk;
196
197 nested->resetTo(pos.inner);
198 }
199
203 void erase(Position const& start, Position const& end, bool recursive = true) {
204 size_t chunkRange = end.chunk - start.chunk;
205
206 if (chunkRange == 0) {
207 chunks[start.chunk]->erase(start.data, end.data);
208 } else {
209 // Treat first chunk.
210 chunks[start.chunk]->erase(start.data, chunks[start.chunk]->getUsedSize());
211
212 // Treat last chunk.
213 chunks[end.chunk]->erase(0, end.data);
214
215 // Erase completely covered chunks and free their memory. Covers also the case that there is no such chunk.
216 chunks.erase(chunks.begin() + start.chunk + 1, chunks.begin() + end.chunk);
217 }
218
219 if (recursive) {
220 nested->erase(start.inner, end.inner, recursive);
221 }
222 }
223
224 /*******************************************************************************/
226
228 CODI_INLINE size_t getDataSize() const {
229 size_t size = 0;
230 for (size_t i = 0; i < chunks.size(); ++i) {
231 size += chunks[i]->getUsedSize();
232 }
233
234 return size;
235 }
236
239 return Position(curChunkIndex, curChunk->getUsedSize(), nested->getPosition());
240 }
241
244 return curChunk->getUsedSize() - startPos;
245 }
246
249 return Position(0, 0, nested->getZeroPosition());
250 }
251
252 /*******************************************************************************/
255
258 void addToTapeValues(TapeValues& values) const {
259 size_t numberOfChunks = chunks.size();
260 size_t dataEntries = getDataSize();
261 size_t entrySize = Chunk::EntrySize;
262
263 double memoryUsed = (double)dataEntries * (double)entrySize;
264 double memoryAlloc = (double)numberOfChunks * (double)chunkSize * (double)entrySize;
265
266 values.addUnsignedLongEntry("Total number", dataEntries);
267 values.addUnsignedLongEntry("Number of chunks", numberOfChunks);
268 values.addDoubleEntry("Memory used", memoryUsed, true, false);
269 values.addDoubleEntry("Memory allocated", memoryAlloc, false, true);
270 }
271
273 template<typename TargetPosition, typename = typename enable_if_not_same<TargetPosition, Position>::type>
274 CODI_INLINE TargetPosition extractPosition(Position const& pos) const {
275 return nested->template extractPosition<TargetPosition>(pos.inner);
276 }
277
279 template<typename TargetPosition, typename = typename enable_if_same<TargetPosition, Position>::type>
281 return pos;
282 }
283
286 // Set nested is only called once during the initialization.
287 codiAssert(nullptr == this->nested);
288 codiAssert(v->getZeroPosition() == v->getPosition());
289
290 this->nested = v;
291
292 curChunk = new Chunk(chunkSize);
293 chunks.push_back(curChunk);
294 positions.push_back(nested->getZeroPosition());
295 }
296
299 std::swap(chunks, other.chunks);
300 std::swap(positions, other.positions);
301 std::swap(curChunkIndex, other.curChunkIndex);
302 std::swap(chunkSize, other.chunkSize);
303
304 curChunk = chunks[curChunkIndex];
305 other.curChunk = other.chunks[other.curChunkIndex];
306
307 nested->swap(*other.nested);
308 }
309
310 /*******************************************************************************/
312
314 template<int selectedDepth = -1, typename FunctionObject, typename... Args>
315 CODI_INLINE void evaluateForward(Position const& start, Position const& end, FunctionObject function,
316 Args&&... args) {
318
319 size_t curDataPos = start.data;
320 size_t endDataPos;
321 NestedPosition curInnerPos = start.inner;
322 NestedPosition endInnerPos;
323
324 size_t curChunk = start.chunk;
325 for (;;) {
326 // Update of end conditions.
327 if (curChunk != end.chunk) {
328 endInnerPos = positions[curChunk + 1];
329 endDataPos = chunks[curChunk]->getUsedSize();
330 } else {
331 endInnerPos = end.inner;
332 endDataPos = end.data;
333 }
334
335 pHandle.setPointers(0, chunks[curChunk]);
336 pHandle.template callNestedForward<selectedDepth - 1>(
337 /* arguments for callNestedForward */
338 nested, curDataPos, endDataPos,
339 /* arguments for nested->evaluateForward */
340 curInnerPos, endInnerPos, function, std::forward<Args>(args)...);
341
342 // After a full chunk is evaluated, the data position needs to be at the end data position.
343 codiAssert(curDataPos == endDataPos);
344
345 if (curChunk != end.chunk) {
346 curChunk += 1;
347 curInnerPos = endInnerPos;
348 curDataPos = 0;
349 } else {
350 break;
351 }
352 }
353 }
354
356 template<int selectedDepth = -1, typename FunctionObject, typename... Args>
357 CODI_INLINE void evaluateReverse(Position const& start, Position const& end, FunctionObject function,
358 Args&&... args) {
360
361 size_t curDataPos = start.data;
362 size_t endDataPos;
363 NestedPosition curInnerPos = start.inner;
364 NestedPosition endInnerPos;
365
366 size_t curChunk = start.chunk;
367 for (;;) {
368 // Update of end conditions.
369 if (curChunk != end.chunk) {
370 endInnerPos = positions[curChunk];
371 endDataPos = 0;
372 } else {
373 endInnerPos = end.inner;
374 endDataPos = end.data;
375 }
376
377 pHandle.setPointers(0, chunks[curChunk]);
378
379 pHandle.template callNestedReverse<selectedDepth - 1>(
380 /* arguments for callNestedReverse */
381 nested, curDataPos, endDataPos,
382 /* arguments for nested->evaluateReverse */
383 curInnerPos, endInnerPos, function, std::forward<Args>(args)...);
384
385 // After a full chunk is evaluated, the data position needs to be at the end data position.
386 codiAssert(curDataPos == endDataPos);
387
388 if (curChunk != end.chunk) {
389 // Update of loop variables.
390 curChunk -= 1;
391 curInnerPos = endInnerPos;
392 curDataPos = chunks[curChunk]->getUsedSize();
393 } else {
394 break;
395 }
396 }
397 }
398
400 template<typename FunctionObject, typename... Args>
401 CODI_INLINE void forEachChunk(FunctionObject& function, bool recursive, Args&&... args) {
402 for (size_t chunkPos = 0; chunkPos < chunks.size(); chunkPos += 1) {
403 function(chunks[chunkPos], std::forward<Args>(args)...);
404 }
405
406 if (recursive) {
407 nested->forEachChunk(function, recursive, std::forward<Args>(args)...);
408 }
409 }
410
412 template<typename FunctionObject, typename... Args>
413 CODI_INLINE void forEachForward(Position const& start, Position const& end, FunctionObject function,
414 Args&&... args) {
415 codiAssert(start.chunk < end.chunk || (start.chunk == end.chunk && start.data <= end.data));
416 codiAssert(end.chunk < chunks.size());
417
418 size_t dataStart = start.data;
419 for (size_t chunkPos = start.chunk; chunkPos <= end.chunk; chunkPos += 1) {
420 size_t dataEnd;
421 if (chunkPos != end.chunk) {
422 dataEnd = chunks[chunkPos]->getUsedSize();
423 } else {
424 dataEnd = end.data;
425 }
426
427 forEachChunkEntryForward(chunkPos, dataStart, dataEnd, function, std::forward<Args>(args)...);
428
429 dataStart = 0;
430 }
431 }
432
434 template<typename FunctionObject, typename... Args>
435 CODI_INLINE void forEachReverse(Position const& start, Position const& end, FunctionObject function,
436 Args&&... args) {
437 codiAssert(start.chunk > end.chunk || (start.chunk == end.chunk && start.data >= end.data));
438 codiAssert(start.chunk < chunks.size());
439
440 size_t dataStart = start.data;
441 size_t chunkPos = start.chunk;
442
443 // For loop break condition is illformed due to unsigned underflow of chunkPos. The condition would be
444 // chunkPos >= end.chunk which only breaks if chunkPos == -1 when end.chunk == 0. The minus one is not possible
445 // for unsigned types.
446 for (;;) {
447 size_t dataEnd;
448 if (chunkPos != end.chunk) {
449 dataEnd = 0;
450 } else {
451 dataEnd = end.data;
452 }
453
454 forEachChunkEntryReverse(chunkPos, dataStart, dataEnd, function, std::forward<Args>(args)...);
455
456 if (chunkPos == end.chunk) {
457 break;
458 } else {
459 // Decrement of loop variable.
460 chunkPos -= 1;
461 dataStart = chunks[chunkPos]->getUsedSize();
462 }
463 }
464 }
465
467
468 private:
469
470 template<typename FunctionObject, typename... Args>
471 CODI_INLINE void forEachChunkEntryForward(size_t const& chunkPos, size_t const& start, size_t const& end,
472 FunctionObject function, Args&&... args) {
473 codiAssert(start <= end);
474 codiAssert(chunkPos < chunks.size());
475
476 PointerInserter pHandle;
477
478 for (size_t dataPos = start; dataPos < end; dataPos += 1) {
479 pHandle.setPointers(dataPos, chunks[chunkPos]);
480 pHandle.call(function, std::forward<Args>(args)...);
481 }
482 }
483
484 template<typename FunctionObject, typename... Args>
485 CODI_INLINE void forEachChunkEntryReverse(size_t const& chunkPos, size_t const& start, size_t const& end,
486 FunctionObject function, Args&&... args) {
487 codiAssert(start >= end);
488 codiAssert(chunkPos < chunks.size());
489
490 PointerInserter pHandle;
491
492 // For loop break condition is illformed due to unsigned underflow of dataPos. The condition would be
493 // dataPos >= end which only breaks if dataPos == -1 when end == 0. The minus one is not possible
494 // for unsigned types.
495 for (size_t dataPos = start; dataPos > end; /* decrement is done inside the loop */) {
496 dataPos -= 1; // Decrement of loop variable.
497
498 pHandle.setPointers(dataPos, chunks[chunkPos]);
499 pHandle.call(function, std::forward<Args>(args)...);
500 }
501 }
502
504 CODI_NO_INLINE void nextChunk() {
505 curChunkIndex += 1;
506 if (chunks.size() == curChunkIndex) {
507 curChunk = new Chunk(chunkSize);
508 chunks.push_back(curChunk);
509 positions.push_back(nested->getPosition());
510 } else {
511 curChunk = chunks[curChunkIndex];
512 curChunk->reset();
513 positions[curChunkIndex] = nested->getPosition();
514 }
515 }
516 };
517
519 template<typename Chunk, typename NestedData = EmptyData>
521}
#define CODI_NO_INLINE
See codi::Config::AvoidedInlines.
Definition: config.h:417
#define CODI_INLINE
See codi::Config::ForcedInlines.
Definition: config.h:457
#define codiAssert(x)
See codi::Config::EnableAssert.
Definition: config.h:432
#define CODI_DD(Type, Default)
Abbreviation for CODI_DECLARE_DEFAULT.
Definition: macros.hpp:94
#define CODI_T(...)
Abbreviation for CODI_TEMPLATE.
Definition: macros.hpp:111
CoDiPack - Code Differentiation Package.
Definition: codi.hpp:90
size_t data
Array position index.
Definition: position.hpp:107
NestedPosition inner
Position of nested data.
Definition: position.hpp:109
Definition: chunk.hpp:185
Position with two indices for e.g. chunked data access.
Definition: position.hpp:166
size_t chunk
Chunk position index.
Definition: position.hpp:172
Data is stored chunk-wise in this DataInterface implementation. If a chunk runs out of space,...
Definition: chunkedData.hpp:64
void setNested(NestedData *v)
Definition: chunkedData.hpp:285
typename std::conditional< selectedDepth==0, TerminatingPointerStore< PointerInserter >, PointerInserter >::type NestingDepthPointerInserter
For selectedDepth == 0 create a pointer inserter that calls the function object.
Definition: chunkedData.hpp:78
ChunkPosition< NestedPosition > Position
Contains position data for this DataInterface and all nested interfaces. "
Definition: chunkedData.hpp:80
void forEachForward(Position const &start, Position const &end, FunctionObject function, Args &&... args)
Calls the function object for each item in the data stream. This call is not recursive.
Definition: chunkedData.hpp:413
T_NestedData NestedData
See ChunkedData.
Definition: chunkedData.hpp:68
size_t getDataSize() const
Definition: chunkedData.hpp:228
typename NestedData::Position NestedPosition
Position of NestedData.
Definition: chunkedData.hpp:72
void pushData(Data const &... data)
Add data to the storage allocated by the implementation. The method can only be called after a call t...
Definition: chunkedData.hpp:117
Position getPosition() const
Definition: chunkedData.hpp:238
void addToTapeValues(TapeValues &values) const
Add amount of stored data to the TapeValues object. Not called on the nested vector.
Definition: chunkedData.hpp:258
void getDataPointers(Data *&... pointers)
Get pointers to the data from the storage implementation. The method can only be called after a call ...
Definition: chunkedData.hpp:124
ChunkedData(size_t const &chunkSize, NestedData *nested)
Allocate chunkSize entries and set the nested DataInterface.
Definition: chunkedData.hpp:96
T_PointerInserter PointerInserter
See ChunkedData.
Definition: chunkedData.hpp:69
InternalPosHandle reserveItems(size_t const &items)
Reserve this many items on the data stream. See pushData for details.
Definition: chunkedData.hpp:137
TargetPosition extractPosition(Position const &pos) const
Extract the position of a nested DataInterface from the global position object provide by this interf...
Definition: chunkedData.hpp:274
ChunkedData(size_t const &chunkSize)
Allocate chunkSize entries. Requires a call to setNested.
Definition: chunkedData.hpp:102
T_Chunk Chunk
See ChunkedData.
Definition: chunkedData.hpp:67
void swap(ChunkedData< Chunk, NestedData > &other)
Definition: chunkedData.hpp:298
void forEachChunk(FunctionObject &function, bool recursive, Args &&... args)
Calls the function object for each continuous segment of data.
Definition: chunkedData.hpp:401
void erase(Position const &start, Position const &end, bool recursive=true)
Definition: chunkedData.hpp:203
void evaluateReverse(Position const &start, Position const &end, FunctionObject function, Args &&... args)
Evaluates the function object with segments of continuous and valid data for all nested DataInterface...
Definition: chunkedData.hpp:357
Position getZeroPosition() const
Definition: chunkedData.hpp:248
void resetTo(Position const &pos)
Definition: chunkedData.hpp:185
void addDataSize(size_t size)
Add this many items to the data stream, after the data has been manipulated via pointers obtained fro...
Definition: chunkedData.hpp:130
void reset()
Definition: chunkedData.hpp:164
void resetHard()
Definition: chunkedData.hpp:169
~ChunkedData()
Destructor.
Definition: chunkedData.hpp:106
void evaluateForward(Position const &start, Position const &end, FunctionObject function, Args &&... args)
Evaluates the function object with segments of continuous and valid data for all nested DataInterface...
Definition: chunkedData.hpp:315
void resize(size_t const &totalSize)
Definition: chunkedData.hpp:151
Position extractPosition(Position const &pos) const
Extract the position of a nested DataInterface from the global position object provide by this interf...
Definition: chunkedData.hpp:280
size_t InternalPosHandle
Position in the chunk.
Definition: chunkedData.hpp:71
size_t getPushedDataCount(InternalPosHandle const &startPos)
Definition: chunkedData.hpp:243
void forEachReverse(Position const &start, Position const &end, FunctionObject function, Args &&... args)
Calls the function object for each item in the data stream. This call is not recursive.
Definition: chunkedData.hpp:435
Data stream interface for tape data. Encapsulates data that is written e.g. for each statement or arg...
Definition: dataInterface.hpp:149
Inserts data pointers at the back of all arguments in the nested call hierarchy.
Definition: pointerStore.hpp:72
Tape information that can be printed in a pretty print format or a table format.
Definition: tapeValues.hpp:73
void addDoubleEntry(std::string const &name, double const &value, bool usedMem=false, bool allocatedMem=false)
Add double entry. If it is a memory entry, it should be in bytes.
Definition: tapeValues.hpp:126
void addUnsignedLongEntry(std::string const &name, unsigned long const &value)
Add unsigned long entry.
Definition: tapeValues.hpp:150