diff --git a/src/paralleltimertree.cpp b/src/paralleltimertree.cpp
index 3036286e..e294f846 100644
--- a/src/paralleltimertree.cpp
+++ b/src/paralleltimertree.cpp
@@ -31,7 +31,6 @@ License along with this library. If not, see .
#include "paralleltimertree.hpp"
#include "prettyprinttable.hpp"
#include "common.hpp"
-
#ifdef _OPENMP
#include "omp.h"
#endif
@@ -490,6 +489,79 @@ bool ParallelTimerTree::printTimers(double minFraction, const std::map &elements,
+ const std::string &delim) -> std::string {
+ if (elements.empty()) {
+ return "";
+ }
+ std::string result = elements[0];
+ for (std::size_t i = 1; i < elements.size(); ++i) {
+ result += delim + elements[i];
+ }
+ return result;
+ };
+
+ if (rankInPrint == 0) {
+ if (stats.id.empty()) {
+ return true;
+ }
+
+ std::vector exclusiveTimeSum = stats.timeSum;
+ std::vector parentIndexStack;
+ // Calculate exclusive timers for flamegraph by removing children
+ for (std::size_t i = 1; i < stats.id.size(); ++i) {
+ const int currentLevel = stats.level[i];
+ while (!parentIndexStack.empty() &&
+ stats.level[parentIndexStack.back()] >= currentLevel) {
+ parentIndexStack.pop_back();
+ }
+
+ if (!parentIndexStack.empty()) {
+ int parentIndex = parentIndexStack.back();
+ exclusiveTimeSum[parentIndex] -= stats.timeSum[i];
+ }
+ parentIndexStack.push_back(i);
+ }
+
+ std::ofstream f(filename);
+ if (!f.is_open()) {
+ std::cerr << "Error: Could not open file for writing flamegraph data: "
+ << filename << std::endl;
+ return false;
+ }
+
+ std::vector stack;
+ for (unsigned int i = 0; i < stats.id.size(); i++) {
+ const int id = stats.id[i];
+ const int level = stats.level[i];
+
+ if (level < 0) {
+ continue;
+ }
+
+ std::string label;
+ if (id != -1) {
+ label = (*this)[id].getLabel();
+ } else {
+ label = "Unknown element";
+ }
+
+ stack.resize(level);
+ stack.push_back(label);
+
+ auto value = 1.0e3 * exclusiveTimeSum[i];
+ f << join(stack, ";") << " " << value << "\n";
+ }
+ f.close();
+ }
+ return true;
+}
//print out global timers
//If any labels differ, then this print will deadlock. Only call it with a communicator that is guaranteed to be consistent on all processes.
@@ -736,6 +808,13 @@ bool ParallelTimerTree::print(MPI_Comm communicator, std::string fileNamePrefix)
}
output.close();
}
+ //Generate detailed flamegraph file
+ std::stringstream fname_flamegraph;
+ fname_flamegraph << fileNamePrefix << "_flamegraph"<< ".txt";
+ if (!generateFlameGraphDataFile(fname_flamegraph.str())){
+ std::cerr << "ERROR: Failed to generate flamegraph file!" << std::endl;
+ }
+
MPI_Comm_free(&printComm);
}
diff --git a/src/paralleltimertree.hpp b/src/paralleltimertree.hpp
index 1c3a6ba7..4370d694 100644
--- a/src/paralleltimertree.hpp
+++ b/src/paralleltimertree.hpp
@@ -114,6 +114,8 @@ class ParallelTimerTree: public TimerTree {
const std::map &groupIds,
std::ofstream &output);
+ bool generateFlameGraphDataFile(const std::string &outputPath);
+
bool printGroupStatistics(double minFraction,
const std::map &groupIds,
std::ofstream &output);