CoDiPack  3.0.0
A Code Differentiation Package
SciComp TU Kaiserslautern
Loading...
Searching...
No Matches
tapeValues.hpp
1/*
2 * CoDiPack, a Code Differentiation Package
3 *
4 * Copyright (C) 2015-2025 Chair for Scientific Computing (SciComp), University of Kaiserslautern-Landau
5 * Homepage: http://scicomp.rptu.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://scicomp.rptu.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 <iomanip>
38#include <sstream>
39#include <string>
40#include <vector>
41
42#include "../../config.h"
43#include "../../misc/exceptions.hpp"
44
46namespace codi {
47
75 struct TapeValues {
76 public:
77 enum class LocalReductionOperation {
78 Sum,
79 Max
80 };
81
82 private:
83 enum class EntryType {
84 Double,
85 Long,
86 UnsignedLong
87 };
88
89 struct Entry {
90 public:
91 std::string name;
92 EntryType type;
93 LocalReductionOperation operation;
94 size_t pos;
95
96 Entry() : name(), type(), operation(), pos() {}
97
98 Entry(std::string const& name, EntryType const& type, LocalReductionOperation const& operation,
99 size_t const& pos)
100 : name(name), type(type), operation(operation), pos(pos) {}
101 };
102
103 struct Section {
104 public:
105 std::string name;
106 std::vector<Entry> data;
107
108 Section() : name(), data() {}
109
110 Section(std::string const& name) : name(name), data() {}
111 };
112
113 std::vector<Section> sections;
114
115 std::vector<double> doubleData;
116 std::vector<long> longData;
117 std::vector<unsigned long> unsignedLongData;
118
119 size_t usedMemoryIndex;
120 size_t allocatedMemoryIndex;
121
122 public:
123
125 TapeValues(std::string const& tapeName)
126 : sections(), doubleData(), longData(), unsignedLongData(), usedMemoryIndex(0), allocatedMemoryIndex(1) {
127 addSection(tapeName);
128 addEntryInternal("Total memory used", EntryType::Double, LocalReductionOperation::Sum, doubleData, 0.0);
129 addEntryInternal("Total memory allocated", EntryType::Double, LocalReductionOperation::Sum, doubleData, 0.0);
130 }
131
132 /*******************************************************************************/
135
137 void addDoubleEntry(std::string const& name, double const& value,
138 LocalReductionOperation operation = LocalReductionOperation::Sum, bool usedMem = false,
139 bool allocatedMem = false) {
140 addEntryInternal(name, EntryType::Double, operation, doubleData, value);
141
142 if (usedMem) {
143 doubleData[usedMemoryIndex] += value;
144 }
145
146 if (allocatedMem) {
147 doubleData[allocatedMemoryIndex] += value;
148 }
149 }
150
152 void addLongEntry(std::string const& name, long const& value,
153 LocalReductionOperation operation = LocalReductionOperation::Sum) {
154 addEntryInternal(name, EntryType::Long, operation, longData, value);
155 }
156
158 void addSection(std::string const& name) {
159 sections.push_back(Section(name));
160 }
161
163 void addUnsignedLongEntry(std::string const& name, unsigned long const& value,
164 LocalReductionOperation operation = LocalReductionOperation::Sum) {
165 addEntryInternal(name, EntryType::UnsignedLong, operation, unsignedLongData, value);
166 }
167
169 /*******************************************************************************/
172
174 template<typename Stream = std::ostream>
175 void formatDefault(Stream& out = std::cout) const {
176 std::string const hLine = "-------------------------------------\n";
177
178 size_t maxNameSize = getMaximumNameLength();
179 size_t maxValueSize = std::max((size_t)10, getMaximumValueLength());
180
181 out << hLine;
182 for (Section const& section : sections) {
183 out << std::left << section.name << "\n";
184 out << hLine;
185
186 for (Entry const& entry : section.data) {
187 out << " " << std::left << std::setw(maxNameSize) << entry.name << " : "
188 << formatEntry(entry, maxValueSize) << "\n";
189 }
190
191 if (!section.data.empty()) {
192 out << hLine;
193 }
194 }
195 }
196
198 template<typename Stream = std::ostream>
199 void formatHeader(Stream& out = std::cout) const {
200 bool first = true;
201 for (Section const& section : sections) {
202 for (Entry const& entry : section.data) {
203 if (first) {
204 first = false;
205 } else {
206 out << "; ";
207 }
208 out << section.name << "-" << entry.name;
209 }
210 }
211
212 out << "\n";
213 }
214
216 template<typename Stream = std::ostream>
217 void formatRow(Stream& out = std::cout) const {
218 size_t maxValueSize = std::max((size_t)10, getMaximumValueLength());
219
220 bool first = true;
221 for (Section const& section : sections) {
222 for (Entry const& entry : section.data) {
223 if (first) {
224 first = false;
225 } else {
226 out << "; ";
227 }
228 out << formatEntry(entry, maxValueSize);
229 }
230 }
231
232 out << "\n";
233 }
234
236 /*******************************************************************************/
239
241 void combineData(TapeValues const& other) {
242 // Size check for the number of sections.
243 codiAssert(this->sections.size() == other.sections.size());
244
245 for (size_t section = 0; section < this->sections.size(); ++section) {
246 auto& thisSection = this->sections[section];
247 auto const& otherSection = other.sections[section];
248
249 // Basic check to ensure that we combine identically structured tape values.
250 codiAssert(thisSection.name == otherSection.name);
251
252 // Size check for the number of entries.
253 codiAssert(thisSection.data.size() == otherSection.data.size());
254
255 for (size_t entry = 0; entry < thisSection.data.size(); ++entry) {
256 auto& thisEntry = thisSection.data[entry];
257 auto const& otherEntry = otherSection.data[entry];
258
259 // Basic checks to ensure that we combine identically structured tape values.
260 codiAssert(thisEntry.name == otherEntry.name);
261 codiAssert(thisEntry.type == otherEntry.type);
262 codiAssert(thisEntry.operation == otherEntry.operation);
263
264 switch (thisEntry.type) {
265 case EntryType::Double: {
266 performLocalReduction(this->doubleData[thisEntry.pos], other.doubleData[otherEntry.pos],
267 thisEntry.operation);
268 break;
269 }
270 case EntryType::Long: {
271 performLocalReduction(this->longData[thisEntry.pos], other.longData[otherEntry.pos],
272 thisEntry.operation);
273 break;
274 }
275 case EntryType::UnsignedLong: {
276 performLocalReduction(this->unsignedLongData[thisEntry.pos], other.unsignedLongData[otherEntry.pos],
277 thisEntry.operation);
278 break;
279 }
280 }
281 }
282 }
283 }
284
289 void combineData() {
290#ifdef MPI_VERSION
291 combineDataMPI(MPI_COMM_WORLD);
292#endif
293 }
294
296#ifdef MPI_VERSION
297 void combineDataMPI(MPI_Comm communicator) {
298 MPI_Allreduce(MPI_IN_PLACE, doubleData.data(), doubleData.size(), MPI_DOUBLE, MPI_SUM, communicator);
299 MPI_Allreduce(MPI_IN_PLACE, longData.data(), longData.size(), MPI_LONG, MPI_SUM, communicator);
300 MPI_Allreduce(MPI_IN_PLACE, unsignedLongData.data(), unsignedLongData.size(), MPI_UNSIGNED_LONG, MPI_SUM,
301 communicator);
302 }
303#else
304 template<typename Comm>
305 void combineDataMPI(Comm communicator) {
306 CODI_UNUSED(communicator);
307 }
308#endif
309
312 return doubleData[allocatedMemoryIndex];
313 }
314
317 return doubleData[usedMemoryIndex];
318 }
319
322 if (this->sections.size() != other.sections.size() || this->doubleData.size() != other.doubleData.size() ||
323 this->longData.size() != other.longData.size() ||
324 this->unsignedLongData.size() != other.unsignedLongData.size()) {
325 CODI_EXCEPTION("Tape values have not the same number of entries.");
326 }
327
328 TapeValues result = *this;
329 for (size_t i = 0; i < result.doubleData.size(); i += 1) {
330 result.doubleData[i] -= other.doubleData[i];
331 }
332 for (size_t i = 0; i < result.longData.size(); i += 1) {
333 result.longData[i] -= other.longData[i];
334 }
335 for (size_t i = 0; i < result.unsignedLongData.size(); i += 1) {
336 result.unsignedLongData[i] -= other.unsignedLongData[i];
337 }
338
339 return result;
340 }
341
343
344 private:
345
346 template<typename T>
347 void performLocalReduction(T& lhs, T const& rhs, LocalReductionOperation operation) {
348 switch (operation) {
349 case LocalReductionOperation::Sum: {
350 lhs += rhs;
351 break;
352 }
353 case LocalReductionOperation::Max: {
354 lhs = std::max(lhs, rhs);
355 break;
356 }
357 }
358 }
359
360 template<typename T>
361 void addEntryInternal(std::string const& name, EntryType const& type, LocalReductionOperation const& operation,
362 std::vector<T>& vector, T const& value) {
363 size_t entryPos = vector.size();
364 vector.push_back(value);
365
366 if (sections.empty()) {
367 addSection("General");
368 }
369
370 sections.back().data.push_back(Entry(name, type, operation, entryPos));
371 }
372
373 std::string formatEntry(Entry const& entry, int maximumFieldSize) const {
374 return formatEntryFull(entry, true, maximumFieldSize);
375 }
376
377 std::string formatEntryFull(Entry const& entry, bool outputType, int maximumFieldSize) const {
378 std::stringstream ss;
379
380 switch (entry.type) {
381 case EntryType::Double: {
382 double formattedData = doubleData[entry.pos];
383 std::string typeString = "";
384
385 if (outputType) {
386 formatSizeHumanReadable(formattedData, typeString);
387 }
388 ss << std::right << std::setiosflags(std::ios::fixed) << std::setprecision(2) << std::setw(maximumFieldSize)
389 << formattedData << typeString;
390 } break;
391 case EntryType::Long:
392 ss << std::right << std::setw(maximumFieldSize) << longData[entry.pos];
393 break;
394 case EntryType::UnsignedLong:
395 ss << std::right << std::setw(maximumFieldSize) << unsignedLongData[entry.pos];
396 break;
397 default:
398 CODI_EXCEPTION("Unimplemented switch case.");
399 break;
400 }
401
402 return ss.str();
403 }
404
405 size_t formatEntryLength(Entry const& entry) const {
406 return formatEntryFull(entry, false, 0).size();
407 }
408
409 void formatSizeHumanReadable(double& size, std::string& type) const {
410 char const* const typeList[] = {"B", "KB", "MB", "GB", "TB"};
411 size_t typeListSize = sizeof(typeList) / sizeof(typeList[0]);
412
413 size_t pos = 0;
414 while (pos < typeListSize && size > 1024.0) {
415 size /= 1024.0;
416 pos += 1;
417 }
418
419 type = " ";
420 type += typeList[pos];
421 }
422
423 size_t getMaximumNameLength() const {
424 size_t maxLength = 0;
425 for (Section const& section : sections) {
426 for (Entry const& data : section.data) {
427 maxLength = std::max(maxLength, data.name.size());
428 }
429 }
430
431 return maxLength;
432 }
433
434 size_t getMaximumValueLength() const {
435 size_t maxLength = 0;
436 for (Section const& section : sections) {
437 for (Entry const& data : section.data) {
438 maxLength = std::max(maxLength, formatEntryLength(data));
439 }
440 }
441
442 return maxLength;
443 }
444 };
445}
#define codiAssert(x)
See codi::Config::EnableAssert.
Definition config.h:441
CoDiPack - Code Differentiation Package.
Definition codi.hpp:94
inlinevoid CODI_UNUSED(Args const &...)
Disable unused warnings for an arbitrary number of arguments.
Definition macros.hpp:54
void combineDataMPI(Comm communicator)
Perform an MPI_Allreduce with the given communicator.
Definition tapeValues.hpp:305
double getAllocatedMemorySize()
Get the allocated memory in bytes.
Definition tapeValues.hpp:311
void addLongEntry(std::string const &name, long const &value, LocalReductionOperation operation=LocalReductionOperation::Sum)
Add long entry.
Definition tapeValues.hpp:152
TapeValues(std::string const &tapeName)
Constructor.
Definition tapeValues.hpp:125
double getUsedMemorySize()
Get the used memory in bytes.
Definition tapeValues.hpp:316
void formatHeader(Stream &out=std::cout) const
Output the header for a table output.
Definition tapeValues.hpp:199
void addUnsignedLongEntry(std::string const &name, unsigned long const &value, LocalReductionOperation operation=LocalReductionOperation::Sum)
Add unsigned long entry.
Definition tapeValues.hpp:163
void formatDefault(Stream &out=std::cout) const
Output in a human readable format. One row per entry.
Definition tapeValues.hpp:175
void formatRow(Stream &out=std::cout) const
Output this data in one row. One entry per column.
Definition tapeValues.hpp:217
void combineData()
Perform an MPI_Allreduce with MPI_COMM_WORLD.
Definition tapeValues.hpp:289
void combineData(TapeValues const &other)
Perform entry-wise additions.
Definition tapeValues.hpp:241
void addDoubleEntry(std::string const &name, double const &value, LocalReductionOperation operation=LocalReductionOperation::Sum, bool usedMem=false, bool allocatedMem=false)
Add double entry. If it is a memory entry, it should be in bytes.
Definition tapeValues.hpp:137
void addSection(std::string const &name)
Add section. All further entries are added under this section.
Definition tapeValues.hpp:158
TapeValues subtract(TapeValues const &other)
Performs 'this - other' on all values provided by the tape.
Definition tapeValues.hpp:321