diff --git a/.gitignore b/.gitignore
index 3df73a0..e4058d0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,10 @@
.cache
build
cmake-build-debug
+stats/*
+!stats/stats
+!stats/stats.cfg
+
.vscode
.idea
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ea34a92..15d4e9d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.19)
-project(motiv VERSION 1.0.0 LANGUAGES CXX)
+project(motiv VERSION 2.2.0 LANGUAGES CXX)
set(PROJECT_SOURCE_URL https://github.com/parcio/motiv)
set(PROJECT_ISSUES_URL ${PROJECT_SOURCE_URL}/issues)
@@ -27,8 +27,10 @@ set(PROJECT_SOURCES
src/ReaderCallbacks.cpp
src/main.cpp
src/models/AppSettings.cpp
+ src/models/ColorMap.cpp
src/models/Filetrace.cpp
src/models/Filter.cpp
+ src/models/Search.cpp
src/models/Slot.cpp
src/models/SubTrace.cpp
src/models/UITrace.cpp
@@ -43,6 +45,7 @@ set(PROJECT_SOURCES
src/models/communication/NonBlockingReceiveEvent.cpp
src/models/communication/NonBlockingSendEvent.cpp
src/models/communication/RequestCancelledEvent.cpp
+ src/models/mpianalysis/Node.cpp
src/ui/ColorGenerator.cpp
src/ui/ColorSynchronizer.cpp
src/ui/widgets/InformationDock.cpp
@@ -51,7 +54,9 @@ set(PROJECT_SOURCES
src/ui/TraceDataProxy.cpp
src/ui/views/CollectiveCommunicationIndicator.cpp
src/ui/views/CommunicationIndicator.cpp
+ src/ui/views/FlamegraphView.cpp
src/ui/views/GenericIndicator.cpp
+ src/ui/views/NodeIndicator.cpp
src/ui/views/SlotIndicator.cpp
src/ui/views/TimelineView.cpp
src/ui/views/TraceOverviewTimelineView.cpp
@@ -68,10 +73,15 @@ set(PROJECT_SOURCES
src/ui/widgets/infostrategies/InformationDockElementBaseStrategy.cpp
src/ui/widgets/infostrategies/InformationDockSlotStrategy.cpp
src/ui/widgets/infostrategies/InformationDockTraceStrategy.cpp
+ src/ui/widgets/mpianalysis/LogicalClock.cpp
src/ui/windows/FilterPopup.cpp
+ src/ui/windows/FlamegraphPopup.cpp
src/ui/windows/MainWindow.cpp
+ src/ui/windows/MpiAnalysisWindow.cpp
src/ui/windows/Otf2FileDialog.cpp
src/ui/windows/RecentFilesDialog.cpp
+ src/ui/windows/SearchPopup.cpp
+ src/ui/windows/SettingsPopup.cpp
src/utils.cpp
)
@@ -109,3 +119,10 @@ install(TARGETS ${PROJECT_NAME}
BUNDLE DESTINATION .)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/motiv.desktop DESTINATION share/applications)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/motiv.png DESTINATION share/icons)
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/buttons/book.png DESTINATION share/icons/buttons)
+
+file(GLOB BUTTON_PNG_FILES "${CMAKE_CURRENT_SOURCE_DIR}/res/buttons/*.png")
+foreach(PNG_FILE ${BUTTON_PNG_FILES})
+ install(FILES ${PNG_FILE} DESTINATION share/icons/buttons)
+endforeach()
+
diff --git a/README.md b/README.md
index 5c3c2ba..7fbc028 100644
--- a/README.md
+++ b/README.md
@@ -26,3 +26,5 @@ The code documentation is generated and available at [parcio.github.io/motiv](ht
MOTIV is licensed under GPL v3 or later. The license is available [here](COPYING).
[Jellyfish icon](https://www.flaticon.com/free-icons/jellyfish) created by [Freepik](https://www.flaticon.com/authors/freepik) from [Flaticon](https://www.flaticon.com/).
+
+[Buttons](https://commons.wikimedia.org/wiki/Tango_icons).
\ No newline at end of file
diff --git a/res/buttons/book.png b/res/buttons/book.png
new file mode 100755
index 0000000..f8cfe17
Binary files /dev/null and b/res/buttons/book.png differ
diff --git a/res/buttons/minus.png b/res/buttons/minus.png
new file mode 100755
index 0000000..03f6432
Binary files /dev/null and b/res/buttons/minus.png differ
diff --git a/res/buttons/plus.png b/res/buttons/plus.png
new file mode 100755
index 0000000..b454527
Binary files /dev/null and b/res/buttons/plus.png differ
diff --git a/res/buttons/plus_grey.png b/res/buttons/plus_grey.png
new file mode 100755
index 0000000..fcd9993
Binary files /dev/null and b/res/buttons/plus_grey.png differ
diff --git a/res/buttons/refresh.png b/res/buttons/refresh.png
new file mode 100755
index 0000000..d8e1de6
Binary files /dev/null and b/res/buttons/refresh.png differ
diff --git a/res/buttons/zoom_fit.png b/res/buttons/zoom_fit.png
new file mode 100755
index 0000000..4b8c96d
Binary files /dev/null and b/res/buttons/zoom_fit.png differ
diff --git a/res/buttons/zoom_in.png b/res/buttons/zoom_in.png
new file mode 100755
index 0000000..f82c48a
Binary files /dev/null and b/res/buttons/zoom_in.png differ
diff --git a/res/buttons/zoom_out.png b/res/buttons/zoom_out.png
new file mode 100755
index 0000000..11994c6
Binary files /dev/null and b/res/buttons/zoom_out.png differ
diff --git a/res/help.md b/res/help.md
index 721d3ba..ec0e0b6 100644
--- a/res/help.md
+++ b/res/help.md
@@ -1,41 +1,58 @@
-# Views
-
-## Central view
-In the center a visualisation of the otf2 trace is shown.
-
-**Each line** represents the function calls in an MPI rank.
-
-**Each block** represents a function call. Nested calls are shown on top. To see an entire call hover over it. The color of the block indicates its type. By default, these are:
-- MPI calls: green
-- OpenMP calls: red
-- Any other calls: grey
-
-**Arrows** depict MPI communications between ranks.
-
-**Rectangles** stretching over all ranks show collective operations.
-
-## Overview
-On the top an overview of the whole trace is shown. The current selected time window is highlighted.
-
-
-# Usage
-
-## Navigating the view
-
-Use `CTRL` and scroll to **zoom in and out**. Use `SHIFT` and scroll to **move the view horizontally**. Reset the view with *View -> Reset* zoom or press `CTRL+R`. Alternatively, input the start and / or end time in the fields at the bottom of the view and press `ENTER` to zoom to a precise time window.
-
-In addition, click and drag a selection in the overview to select a time window.
-
-## Interactions
-
-Click on any element to see more information on it in the right pane. Click the *Zoom into view* button to zoom to the current selected item.
-
-## Filter
-
-Use *View -> Filter* or press `CTRL+S` to open a filter window.
-
-### Filter function call types
-
-Check or uncheck the kinds of functions that should be shown.
-
+### Basic controls
+#### Notable shortcuts
+- View related options: F1 (filter), F2 (settings), F3 (active thresholds)
+- Zoom out: Space
+- Zoom in:
+ - double click (onto indicators)
+ - CTRL+scroll
+- Move left/right: Shift+scroll
+- Search: CTRL+S
+#### Notable interactions
+- Making a selection:
+ - Click, hold the button and drag (overview) to the left or right to select the required section
+ - Input the start and / or end time in the fields at the bottom of the view and press ENTER
+- Multi-threading view: +/- icons near ranknames
+- Flamegraph view: right click (context menu) onto ranknames
+- Toggle P2P (in and out): right click (context menu) onto ranknames
+- Set custom colors: details pane (per default to the right)
+
+---
+
+### Views
+#### Central view (Selection)
+Each **row** represents an **MPI rank**; when the thread view is expanded, multiple rows can represent a single MPI rank, with one thread per row. The mode of view is indicated by +/- icons:
+- A + means the row can be expanded into the thread view.
+- A - means the row has been expanded into the thread view.
+- A grayed-out + indicates that no multi-threading was detected.
+
+Within and between the rows, there are **various indicators**: (1) rectangular, colored blocks, (2) arrows, and (3) blue frames.
+
+The rectangular blocks within the rows represent **function calls** or recordings of entered regions (often abbreviated as REG). Different functions are assigned different colors:
+- MPI functions are usually yellowish-green.
+- OpenMPI functions are usually red-orange.
+- Other functions are assigned arbitrary colors.
+
+The arrows describe **point-to-point communications** (often abbreviated as P2P) between the ranks or threads, generally between rows.
+
+The blue, rectangular frames that span the rows describe **collective communications** (often abbreviated as CCM); ranks involved are highlighted by hatched function calls within these frames.
+
+#### Overview
+Directly below the upper menu bar is the overview. Here, one can always see the entire trace and also the current selection for the main view.
+
+Differences from the main view include that only functions/regions are displayed here, and docking behavior: This element can be detached from and reattached to the main window.
+
+#### Flamegraph
+Through a context menu regarding the rank names, one has the option to open the flamegraph view, for a particular rank. In this view, similar to the overview, only functions/regions are displayed; however, they are not overlapping but rather stacked according to their runtime into call hierarchies.
+
+This view is always synchronized with the central view or the current selection.
+
+---
+
+### Colors
+#### At start
+Colors are assigned in static steps via RGB-coordinates, there are 159 valid positions between (0|0|0) and (255|255|255) which are assigned in the same order as the functions are encountered (first come, first serve). Encountered functions past these 159 positions will all be assigned white.
+#### During Search
+During a search, functions are assigned gray, except the one being searched for, which is displayed in purple.
+
+---
diff --git a/res/style.qss b/res/style.qss
index ab2bc8f..6326d18 100644
--- a/res/style.qss
+++ b/res/style.qss
@@ -1,5 +1,52 @@
QToolTip {
background-color: black;
color: white;
- border: black solid 1px
+ border: 1px outset #8A8A8A;
+ padding: 1px;
+ font-size: 11pt;
}
+
+QScrollBar:vertical {
+ border: 1px solid #8A8A8A;
+ background: #6B6B6B;
+ width: 10px;
+ margin: 0px 0 0px 0;
+ border-radius: 5px;
+}
+
+QScrollBar::handle:vertical {
+ background: qradialgradient(cx:0.5, cy:0.5, radius:1, fx:0.5, fy:0.5, stop:0 #B0C4DE, stop:1 #FFFFFF);
+ border: 1px solid #8A8A8A;
+ /*for some reason this border-radius is ignored, this causes the quadratic shape of the handle*/
+ border-radius: 5px;
+ margin: 0px 0 0px 0;
+}
+
+QScrollBar::handle:vertical:hover {
+ /* central point & focal point are inverted*/
+ background: qradialgradient(cx:0.5, cy:0.5, radius:1, fx:0.5, fy:0.5, stop:0 #FFFFFF, stop:1 #B0C4DE);
+}
+
+QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
+ height: 0px;
+}
+
+
+QSlider::groove:vertical {
+ border: 1px solid #F5F5F5;
+ background: qradialgradient(cx:0.5, cy:0.5, radius:1, fx:0.5, fy:0.5, stop:0 #C0C0C0, stop:1 #FFFFFF);
+ width: 1px;
+ margin: 2px 0 2px 0;
+}
+
+QSlider::handle:vertical {
+ background: qradialgradient(cx:0.5, cy:0.5, radius:1, fx:0.5, fy:0.5, stop:0 #B0C4DE, stop:1 #D3D3D3);
+ border: 1px solid gray;
+ height: 9px;
+ width: 9px;
+ margin: -2px -6px;
+ border-radius: 2px;
+}
+
+
+
diff --git a/resources.qrc b/resources.qrc
index 47e400b..8b5d2ed 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -4,5 +4,13 @@
res/help.md
res/style.qss
res/motiv.png
+ res/buttons/book.png
+ res/buttons/minus.png
+ res/buttons/plus.png
+ res/buttons/plus_grey.png
+ res/buttons/refresh.png
+ res/buttons/zoom_fit.png
+ res/buttons/zoom_in.png
+ res/buttons/zoom_out.png
diff --git a/src/ReaderCallbacks.cpp b/src/ReaderCallbacks.cpp
index eb7c135..331342e 100644
--- a/src/ReaderCallbacks.cpp
+++ b/src/ReaderCallbacks.cpp
@@ -1,6 +1,6 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Florian Gallrein, Björn Gehrke, Jessica Lafontaine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,8 +33,7 @@ ReaderCallbacks::ReaderCallbacks(otf2::reader::reader &rdr) :
collectiveCommunications_(std::vector()),
slotsBuilding(),
program_start_(),
- rdr_(rdr) {
-
+ rdr_(rdr) {
}
@@ -60,36 +59,44 @@ void ReaderCallbacks::event(const otf2::definition::location &, const otf2::even
void ReaderCallbacks::event(const otf2::definition::location &loc, const otf2::event::enter &event) {
- auto start = event.timestamp() - this->program_start_;
-
- Slot::Builder builder{};
- auto region = new otf2::definition::region(event.region());
- auto location = new otf2::definition::location(loc);
- builder.start(start)->location(location)->region(region);
-
- std::vector *builders;
- auto buildersIt = this->slotsBuilding.find(location->ref().get());
- if (buildersIt == this->slotsBuilding.end()) {
- builders = new std::vector();
- this->slotsBuilding.insert({location->ref().get(), builders});
- } else {
- builders = buildersIt->second;
- }
+ if(mode_ == MPI_Analysis && event.region().paradigm() != otf2::common::paradigm_type::mpi){
+ return;
+ }else{
+ auto start = event.timestamp() - this->program_start_;
+
+ Slot::Builder builder{};
+ auto region = new otf2::definition::region(event.region());
+ auto location = new otf2::definition::location(loc);
+ builder.start(start)->location(location)->region(region);
+
+ std::vector *builders;
+ auto buildersIt = this->slotsBuilding.find(location->ref().get());
+ if (buildersIt == this->slotsBuilding.end()) {
+ builders = new std::vector();
+ this->slotsBuilding.insert({location->ref().get(), builders});
+ } else {
+ builders = buildersIt->second;
+ }
- builders->push_back(builder);
+ builders->push_back(builder);
+ }
}
void ReaderCallbacks::event(const otf2::definition::location &location, const otf2::event::leave &event) {
- auto builders = this->slotsBuilding.at(location.ref().get());
+ if(mode_ == MPI_Analysis && event.region().paradigm() != otf2::common::paradigm_type::mpi){
+ return;
+ }else{
+ auto builders = this->slotsBuilding.at(location.ref().get());
- Slot::Builder &builder = builders->back();
+ Slot::Builder &builder = builders->back();
- auto end = event.timestamp() - this->program_start_;
- builder.end(end);
+ auto end = event.timestamp() - this->program_start_;
+ builder.end(end);
- this->slots_.push_back(new Slot(builder.build()));
+ this->slots_.push_back(new Slot(builder.build()));
- builders->pop_back();
+ builders->pop_back();
+ }
}
@@ -100,10 +107,14 @@ void ReaderCallbacks::communicationEvent(T* self, uint32_t matching,
) {
// Check for a pending matching call
if (matchingPending.contains(matching)) {
- auto& matchingEvents = matchingPending[matching];
+ auto& matchingEvents = matchingPending[matching];
auto matchingEvent = matchingEvents->back();
-
- auto communication = new Communication(matchingEvent, self);
+ Communication* communication = nullptr;
+
+ // Check for the source of the start event in non-blocking communication
+ if(matchingEvent->getStartTime()<= self->getStartTime()) communication = new Communication(matchingEvent, self);
+ else communication = new Communication(self, matchingEvent);
+
communications_.push_back(communication);
matchingEvents->pop_back();
@@ -138,7 +149,7 @@ void ReaderCallbacks::event(const otf2::definition::location &loc, const otf2::e
auto comm = new types::communicator(receive.comm());
auto ev = new BlockingReceiveEvent(relative(receive.timestamp()), location, comm);
- this->communicationEvent(ev, receive.sender(), pendingReceives, pendingSends);
+ this->communicationEvent(ev, receive.sender(), pendingReceives, pendingSends);
}
void ReaderCallbacks::event(const otf2::definition::location &location, const otf2::event::mpi_isend_request &request) {
@@ -152,19 +163,18 @@ void ReaderCallbacks::event(const otf2::definition::location &location, const ot
builder.start(start);
builder.receiver(receiver);
- this->uncompletedRequests.insert({request.request_id(), builder});
+ // this->uncompletedIsendRequests.insert({request.request_id(), builder});
+ this->uncompletedIsendRequests[location.ref()].insert({request.request_id(), builder});
}
void
-ReaderCallbacks::event(const otf2::definition::location &, const otf2::event::mpi_isend_complete &complete) {
- if (!uncompletedRequests.contains(complete.request_id())) {
+ReaderCallbacks::event(const otf2::definition::location &location, const otf2::event::mpi_isend_complete &complete) {
+ if (!uncompletedIsendRequests[location.ref()].contains(complete.request_id())) {
throw std::logic_error("Found a mpi_isend_complete event with no matching mpi_isend_request event!");
}
- auto builderVariant = uncompletedRequests[complete.request_id()];
- if(!holds_alternative(builderVariant)) {
- throw std::logic_error("mpi_isend_complete event completes an mpi_ireceive event!");
- }
+ // auto loc = new otf2::definition::location(location);
+ auto builderVariant = uncompletedIsendRequests[location.ref()][complete.request_id()];
auto builder = get(builderVariant);
@@ -173,44 +183,41 @@ ReaderCallbacks::event(const otf2::definition::location &, const otf2::event::mp
auto ev = new NonBlockingSendEvent(builder.build());
- communicationEvent(ev, builder.receiver(), pendingSends, pendingReceives);
+ this->communicationEvent(ev, builder.receiver(), pendingSends, pendingReceives);
}
void
-ReaderCallbacks::event(const otf2::definition::location &, const otf2::event::mpi_ireceive_complete &complete) {
- if (!uncompletedRequests.contains(complete.request_id())) {
+ReaderCallbacks::event(const otf2::definition::location &location, const otf2::event::mpi_ireceive_complete &complete) {
+ if (!uncompletedIrecvRequests[location.ref()].contains(complete.request_id())) {
throw std::logic_error("Found a mpi_ireceive_complete event with no matching mpi_ireceive_request event!");
}
- auto builderVariant = uncompletedRequests[complete.request_id()];
- if(!holds_alternative(builderVariant)) {
- throw std::logic_error("mpi_ireceive_complete event completes an mpi_isend event!");
- }
-
+ // auto builderVariant = uncompletedIrecvRequests[complete.request_id()];
+ auto builderVariant = uncompletedIrecvRequests[location.ref()][complete.request_id()];
auto builder = get(builderVariant);
+ auto comm = new types::communicator (complete.comm());
+ auto sender = complete.sender();
+ builder.communicator(comm);
+ builder.sender(sender);
+
auto end = relative(complete.timestamp());
builder.end(end);
- auto ev = new NonBlockingReceiveEvent(builder.build());
+ auto ev = new NonBlockingReceiveEvent(builder.build());
- communicationEvent(ev, builder.sender(), pendingReceives, pendingSends);
+ this->communicationEvent(ev, builder.sender(), pendingReceives, pendingSends);
}
-void
-ReaderCallbacks::event(const otf2::definition::location &location, const otf2::event::mpi_ireceive_request &request) {
-
+void
+ReaderCallbacks::event(const otf2::definition::location &location, const otf2::event::mpi_ireceive_request &request) {
NonBlockingReceiveEvent::Builder builder;
- auto comm = new types::communicator (request.comm());
auto loc = new otf2::definition::location(location);
- auto start = relative(request.timestamp());
- auto sender = request.sender();
- builder.communicator(comm);
+ auto start = relative(request.timestamp());
builder.location(loc);
builder.start(start);
- builder.sender(sender);
- this->uncompletedRequests.insert({request.request_id(), builder});
+ this->uncompletedIrecvRequests[location.ref()].insert({request.request_id(), builder});
}
void ReaderCallbacks::event(const otf2::definition::location &location, const otf2::event::mpi_request_test &test) {
@@ -235,10 +242,12 @@ ReaderCallbacks::event(const otf2::definition::location &location, const otf2::e
}
void ReaderCallbacks::event(const otf2::definition::location &location, const otf2::event::mpi_collective_end &anEnd) {
+ using CommGroup = otf2::definition::group;
+
if(ongoingCollectiveCommunication == nullptr) {
ongoingCollectiveCommunication = new CollectiveCommunicationEvent::Builder();
std::vector members;
- auto loc = new otf2::definition::location( location);
+ auto loc = new otf2::definition::location(location);
auto comm = new types::communicator (anEnd.comm());
auto operation = anEnd.type();
auto root = anEnd.root();
@@ -256,13 +265,41 @@ void ReaderCallbacks::event(const otf2::definition::location &location, const ot
ongoingCollectiveCommunication->members()->push_back(new CollectiveCommunicationEvent::Member(member.build()));
ongoingCollectiveCommunicationMembers.erase(location.ref().get());
- // If the map is now empty, all ranks have completed the collective operation and the communication event can be build
- if(ongoingCollectiveCommunicationMembers.empty()){
+ // Check the number of members involved in this collective operation
+ size_t MembersSize = 0;
+ const auto& commVariant = anEnd.comm();
+ auto interComm = std::get_if(&commVariant);
+ if (interComm != nullptr) {
+ auto groupA = std::get(interComm->groupA());
+ auto groupB = std::get(interComm->groupB());
+ MembersSize = groupA.size()+groupB.size();
+ } else {
+ auto comm = std::get_if(&commVariant);
+ if (comm != nullptr) {
+ auto& group = std::get(comm->group());
+ MembersSize = group.size();
+ }
+ }
+
+ // If the current number of members equals the actual size of the group,
+ // all ranks have completed the collective operation and the communication event can be build
+ auto currendMembersSize = ongoingCollectiveCommunication->members().get()->size();
+ if(MembersSize == currendMembersSize){
auto event = new CollectiveCommunicationEvent(ongoingCollectiveCommunication->build());
collectiveCommunications_.push_back(event);
delete ongoingCollectiveCommunication;
ongoingCollectiveCommunication = nullptr;
- }
+ }
+
+ // Old version
+ // // If the map is now empty, all ranks have completed the collective operation and the communication event can be build
+ // if(ongoingCollectiveCommunicationMembers.empty()){
+ // auto event = new CollectiveCommunicationEvent(ongoingCollectiveCommunication->build());
+ // collectiveCommunications_.push_back(event);
+ // delete ongoingCollectiveCommunication;
+ // ongoingCollectiveCommunication = nullptr;
+ // }
+
}
@@ -294,7 +331,8 @@ void ReaderCallbacks::events_done(const otf2::reader::reader &) {
std::destroy(this->slotsBuilding.begin(), this->slotsBuilding.end());
std::destroy(this->pendingSends.begin(), this->pendingSends.end());
std::destroy(this->pendingReceives.begin(), this->pendingReceives.end());
- std::destroy(this->uncompletedRequests.begin(), this->uncompletedRequests.end());
+ std::destroy(this->uncompletedIsendRequests.begin(), this->uncompletedIsendRequests.end());
+ std::destroy(this->uncompletedIrecvRequests.begin(), this->uncompletedIrecvRequests.end());
}
otf2::chrono::duration ReaderCallbacks::relative(otf2::chrono::time_point timepoint) const {
diff --git a/src/ReaderCallbacks.hpp b/src/ReaderCallbacks.hpp
index 4741a3d..04f3e9d 100644
--- a/src/ReaderCallbacks.hpp
+++ b/src/ReaderCallbacks.hpp
@@ -1,6 +1,6 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Florian Gallrein, Björn Gehrke, Jessica Lafontaine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,12 +21,15 @@
#include
#include
+#include "src/models/AppSettings.hpp"
#include "src/models/Slot.hpp"
#include "src/models/communication/Communication.hpp"
#include "src/models/communication/NonBlockingSendEvent.hpp"
#include "src/models/communication/NonBlockingReceiveEvent.hpp"
#include "src/models/communication/CollectiveCommunicationEvent.hpp"
+
+
template
using BuilderSetLocation = std::function;
@@ -54,6 +57,8 @@ class ReaderCallbacks : public otf2::reader::callback {
std::vector communications_;
std::vector collectiveCommunications_;
+ Mode mode_ = AppSettings::getInstance().getMode();
+
/**
* Vectors for building the slot datatypes. Key is the location of the events.
*/
@@ -75,7 +80,11 @@ class ReaderCallbacks : public otf2::reader::callback {
/**
* Vectors for building the non blocking communication datatypes. Key is the request id.
*/
- std::map uncompletedRequests;
+ // std::map uncompletedIsendRequests;
+ std::map> uncompletedIsendRequests;
+
+ // std::map uncompletedIrecvRequests;
+ std::map> uncompletedIrecvRequests;
otf2::chrono::time_point program_start_;
otf2::chrono::time_point program_end_;
diff --git a/src/main.cpp b/src/main.cpp
index 9b84b4c..dbfb971 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,6 +1,9 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Florian Gallrein,
+ * Björn Gehrke,
+ * Jessica Lafontaine,
+ * Tomas Cirkov
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +24,7 @@
#include
#include "src/ui/windows/MainWindow.hpp"
+#include "src/ui/windows/MpiAnalysisWindow.hpp"
#include "src/ui/windows/RecentFilesDialog.hpp"
// Decides wether performance information will be printed
@@ -48,10 +52,13 @@ int main(int argc, char *argv[])
QCommandLineOption helpOption = parser.addHelpOption();
QCommandLineOption versionOption = parser.addVersionOption();
- QCommandLineOption testrunOption("t", QCoreApplication::translate("main", "#todo: fitting descr?"), "file");
+ QCommandLineOption testrunOption("t", QCoreApplication::translate("main", "Runs motiv in test mode, i.e. pure trace-loading without GUI representation for benchmark purposes."), "file");
parser.addOption(testrunOption);
parser.addPositionalArgument("file", QCoreApplication::translate("main", "filepath of the .otf2 trace file to open"), "[file]");
+ QCommandLineOption modeOption("m", QCoreApplication::translate("main", "Selects the visualisation mode of Motiv.\n0: Default, 1: MPI Communication"), "mode");
+ parser.addOption(modeOption);
+
parser.process(app);
// Early return if help or version is shown
@@ -65,20 +72,44 @@ int main(int argc, char *argv[])
filepath = positionalArguments.first();
}
+ bool modeValidity = true;
+ int mode = parser.value(modeOption).toInt(&modeValidity);
+
// Test run without window display
if (parser.isSet(testrunOption)){
testRun = true;
- auto dummyWindow = new MainWindow(parser.value(testrunOption));
+ [[maybe_unused]] auto dummyMainWindow = new MpiAnalysisWindow(parser.value(testrunOption));
app.quit();
std::cout << "%application in general%" << appTimer.elapsed() << "%ms%";
return EXIT_SUCCESS;
}
RecentFilesDialog recentFilesDialog(&filepath);
- if(!filepath.isEmpty() || recentFilesDialog.exec() == QDialog::Accepted) {
- auto mainWindow = new MainWindow(filepath);
- qInfo() << "motiv ready";
- mainWindow->show();
+
+ // Swap mode control to run Motiv in alternative mode by default
+ // Also, update mode ID in AppSettings.hpp
+ if((modeValidity || (!parser.isSet(modeOption))) && (!filepath.isEmpty() || recentFilesDialog.exec() == QDialog::Accepted)) {
+ if((!parser.isSet(modeOption)) || mode == 0){
+ // if (parser.isSet(modeOption) && mode == 1){
+ auto mainWindow = new MainWindow(filepath);
+ QString fullTitle;
+ QTextStream text(&fullTitle);
+ text << "Motiv " MOTIV_VERSION_STRING;
+ mainWindow->setWindowTitle(fullTitle);
+ qInfo() << "motiv ready";
+ mainWindow->show();
+ }
+ //if((!parser.isSet(modeOption)) || mode == 0){
+ if (parser.isSet(modeOption) && mode == 1){
+ auto mainWindow = new MpiAnalysisWindow(filepath);
+ QString fullTitle;
+ QTextStream text(&fullTitle);
+ text << "Motiv " MOTIV_VERSION_STRING;
+ mainWindow->setWindowTitle(fullTitle);
+ qInfo() << "motiv ready";
+ mainWindow->show();
+
+ }
} else {
app.quit();
return EXIT_SUCCESS;
diff --git a/src/models/AppSettings.cpp b/src/models/AppSettings.cpp
index b5db60f..65ec9d3 100644
--- a/src/models/AppSettings.cpp
+++ b/src/models/AppSettings.cpp
@@ -1,6 +1,6 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Florian Gallrein, Björn Gehrke, Jessica Lafontaine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -112,4 +112,12 @@ void AppSettings::toggleGlobalColorConfig(bool checked)
bool AppSettings::getuseGlobalColorConfig(){
return this->useGlobalColorConfig;
+}
+
+void AppSettings::setMode(Mode mode){
+ this->mode = mode;
+}
+
+Mode AppSettings::getMode(){
+ return this->mode;
}
\ No newline at end of file
diff --git a/src/models/AppSettings.hpp b/src/models/AppSettings.hpp
index cfdeeda..a41300e 100644
--- a/src/models/AppSettings.hpp
+++ b/src/models/AppSettings.hpp
@@ -1,6 +1,6 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Florian Gallrein, Björn Gehrke, Jessica Lafontaine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,6 +22,14 @@
#include
#include
+// Swap mode ID to run Motiv in alternative mode by default.
+// Also, update mode control in main.cpp.
+enum Mode{
+ Default = 0,
+ MPI_Analysis = 1
+};
+
+
/**
* @brief Singleton holding persistent information.
*
@@ -109,6 +117,10 @@ Q_OBJECT
void clearColorConfig();
bool getuseGlobalColorConfig();
+
+ void setMode(Mode mode);
+
+ Mode getMode();
public: Q_SIGNALS:
/**
@@ -132,6 +144,7 @@ public Q_SLOTS:
QStringList recentlyOpenedFiles_;
QString colorConfigName_;
bool useGlobalColorConfig = false;
+ Mode mode = Default;
};
diff --git a/src/models/ColorMap.cpp b/src/models/ColorMap.cpp
index 5753d5a..d2d0de0 100644
--- a/src/models/ColorMap.cpp
+++ b/src/models/ColorMap.cpp
@@ -1,6 +1,6 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Jessica Lafontaine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/models/ColorMap.hpp b/src/models/ColorMap.hpp
index fc1c6c6..a474fd4 100644
--- a/src/models/ColorMap.hpp
+++ b/src/models/ColorMap.hpp
@@ -1,6 +1,6 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Jessica Lafontaine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/models/Filter.cpp b/src/models/Filter.cpp
index c379d76..528b9a3 100644
--- a/src/models/Filter.cpp
+++ b/src/models/Filter.cpp
@@ -24,3 +24,12 @@ SlotKind Filter::getSlotKinds() const {
void Filter::setSlotKinds(SlotKind slotKinds) {
slotKinds_ = slotKinds;
}
+
+
+CommunicationKind Filter::getCommunicationKinds() const{
+ return communicationKinds_;
+}
+
+void Filter::setCommunicationKind(CommunicationKind communicationKind){
+ communicationKinds_ = communicationKind;
+}
\ No newline at end of file
diff --git a/src/models/Filter.hpp b/src/models/Filter.hpp
index 68af3f1..340ef63 100644
--- a/src/models/Filter.hpp
+++ b/src/models/Filter.hpp
@@ -18,9 +18,11 @@
#ifndef MOTIV_FILTER_HPP
#define MOTIV_FILTER_HPP
-#define FILTER_DEFAULT ((SlotKind) (SlotKind::MPI | SlotKind::OpenMP | SlotKind::Plain))
+#define SLOT_FILTER_DEFAULT ((SlotKind) (SlotKind::MPI | SlotKind::OpenMP | SlotKind::Plain))
+#define COMMUNICATION_FILTER_DEFAULT ((CommunicationKind) (CommunicationKind::PointToPoint | CommunicationKind::Collective | CommunicationKind::Synchronizing))
#include "Slot.hpp"
+#include "src/models/communication/CommunicationKind.hpp"
/**
* @brief Class containing options to filter the view.
@@ -43,8 +45,24 @@ class Filter {
*/
void setSlotKinds(SlotKind slotKinds);
+ /**
+ * @brief Returns the kinds of communication that should be rendered.
+ * @return The kinds of communication that should be rendered.
+ */
+ [[nodiscard]] CommunicationKind getCommunicationKinds() const;
+
+ /**
+ * @brief Sets the communication that should be rendered.
+ *
+ * Note that CommunicationKind values can be used as a flag and be combined with a bitwise or.
+ * @param communicationKinds The kind of communication that should be rendered.
+ */
+ void setCommunicationKind(CommunicationKind communicationKinds);
+
+
private: // fields
- SlotKind slotKinds_ = FILTER_DEFAULT;
+ SlotKind slotKinds_ = SLOT_FILTER_DEFAULT;
+ CommunicationKind communicationKinds_ = COMMUNICATION_FILTER_DEFAULT;
};
diff --git a/src/models/Range.hpp b/src/models/Range.hpp
index d4510c6..5444c7f 100644
--- a/src/models/Range.hpp
+++ b/src/models/Range.hpp
@@ -61,14 +61,17 @@ class Range {
Range(const Range &rhs) {
if (rhs.vec_) {
vec_ = new std::vector(*rhs.vec_);
- begin_ = std::find(vec_->begin(), vec_->end(), *rhs.begin_);
- end_ = std::find(vec_->begin(), vec_->end(), *rhs.end_);
+ auto dist_begin = std::distance(rhs.vec_->begin(), rhs.begin_);
+ auto dist_end = std::distance(rhs.vec_->begin(), rhs.end_);
+ begin_ = vec_->begin() + dist_begin;
+ end_ = vec_->begin() + dist_end;
} else {
begin_ = rhs.begin_;
end_ = rhs.end_;
}
};
+
/**
* Construct a range from a vector.
*
@@ -95,9 +98,14 @@ class Range {
if (rhs.vec_) {
delete vec_;
- vec_ = new std::vector(*rhs.vec_);
- begin_ = std::find(vec_->begin(), vec_->end(), *rhs.begin_);
- end_ = std::find(vec_->begin(), vec_->end(), *rhs.end_);
+ vec_ = new std::vector(*rhs.vec_);
+ // begin_ = std::find(vec_->begin(), vec_->end(), *rhs.begin_);
+ // end_ = std::find(vec_->begin(), vec_->end(), *rhs.end_);
+
+ auto dist_begin = std::distance(rhs.vec_->begin(), rhs.begin_);
+ auto dist_end = std::distance(rhs.vec_->begin(), rhs.end_);
+ begin_ = vec_->begin() + dist_begin;
+ end_ = vec_->begin() + dist_end;
} else {
begin_ = rhs.begin_;
end_ = rhs.end_;
@@ -130,6 +138,14 @@ class Range {
delete vec_;
};
+
+ int getIndexOf(const T &item) const {
+ auto it = std::find(vec_->begin(), vec_->end(), item);
+ if (it != vec_->end()) {
+ return std::distance(vec_->begin(), it);
+ }else return -1;
+ }
+
private:
std::vector *vec_ = nullptr;
It begin_;
diff --git a/src/models/Search.cpp b/src/models/Search.cpp
new file mode 100644
index 0000000..a07539c
--- /dev/null
+++ b/src/models/Search.cpp
@@ -0,0 +1,61 @@
+/*
+ * Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
+ * Copyright (C) 2023 Jessica Lafontaine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#include "src/models/Search.hpp"
+
+Search::Search(TraceDataProxy *data, QListWidget *itemList, QWidget *parent): data(data), itemList(itemList), QListWidget(parent){
+ if(this->data == nullptr) throw std::invalid_argument("data (TraceDataProxy) is null");
+
+ for(const auto &item : data->getFullTrace()->getSlots()){
+ for(const auto &slot: item.second){
+ QString name = QString::fromStdString(slot->region->name().str());
+ QList matches = this->itemList->findItems(name, Qt::MatchExactly);
+ if(matches.isEmpty()) this->itemList->addItem(name);
+ }
+ }
+
+ this->itemList->sortItems(Qt::AscendingOrder);
+}
+
+void Search::findName(QString subname, QListWidget *itemList) {
+ for (int i = 0; i < itemList->count(); i++) {
+ QListWidgetItem *item = itemList->item(i);
+ QString name = item->text();
+ if (!name.contains(subname,Qt::CaseInsensitive)){
+ item->setHidden(true);
+ } else item->setHidden(false);
+ }
+}
+
+
+std::list Search::createItemList(QString searchedName){
+ std::list resultList;
+ for(const auto &item : data->getFullTrace()->getSlots()){
+ for(const auto &slot: item.second){
+ QString name = QString::fromStdString(slot->region->name().str());
+ if(name == searchedName){
+ resultList.push_back(slot);
+ }
+ }
+ }
+ return resultList;
+}
+
diff --git a/src/models/Search.hpp b/src/models/Search.hpp
new file mode 100644
index 0000000..10008cd
--- /dev/null
+++ b/src/models/Search.hpp
@@ -0,0 +1,55 @@
+/*
+ * Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
+ * Copyright (C) 2023 Jessica Lafontaine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef MOTIV_Search_HPP
+#define MOTIV_Search_HPP
+
+#include
+
+#include "src/ui/TraceDataProxy.hpp"
+
+/**
+ * @brief A class for handling search functionality
+ * @note It holds a distinct list of all slot function names.
+ */
+class Search : QListWidget {
+Q_OBJECT
+public:
+ Search(TraceDataProxy *data, QListWidget *itemList, QWidget *parent=nullptr);
+
+ /**
+ * @brief Shortens the item list based on the provided string (hides all other items).
+ * @param string The string to match
+ * @param itemList Pointer to the QListWidget for modification
+ */
+ void findName(QString string, QListWidget *itemList);
+
+ /**
+ * @brief Creates an iteratable item list for "Next" and "Previous" actions (doubly linked).
+ * @param name The name to search for
+ * @return List of TimedElement pointers for iteration
+ */
+ std::list createItemList(QString name);
+
+
+private:
+ QListWidget *itemList = nullptr;
+ TraceDataProxy* data = nullptr;
+
+};
+#endif //MOTIV_Search_HPP
\ No newline at end of file
diff --git a/src/models/Slot.cpp b/src/models/Slot.cpp
index d692b5a..80de547 100644
--- a/src/models/Slot.cpp
+++ b/src/models/Slot.cpp
@@ -1,6 +1,6 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Florian Gallrein, Björn Gehrke, Jessica Lafontaine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/models/ViewSettings.cpp b/src/models/ViewSettings.cpp
index 575e0cf..1309e7c 100644
--- a/src/models/ViewSettings.cpp
+++ b/src/models/ViewSettings.cpp
@@ -1,6 +1,9 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Florian Gallrein,
+ * Björn Gehrke,
+ * Jessica Lafontaine,
+ * Tomas Cirkov
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +20,20 @@
*/
#include "ViewSettings.hpp"
+
+//#todo: delete later
+//#include
+
+ViewSettings* ViewSettings::instance = nullptr_t();
+
+ViewSettings::ViewSettings(){}
+
+ViewSettings* ViewSettings::getInstance()
+{
+ if (instance == nullptr) instance = new ViewSettings();
+ return instance;
+}
+
int ViewSettings::getZoomQuotient() const {
return zoomFactor_;
}
@@ -32,3 +49,168 @@ Filter ViewSettings::getFilter() const {
void ViewSettings::setFilter(Filter filter) {
filter_ = filter;
}
+
+int ViewSettings::getRowHeight() {
+ return this->rowHeight;
+}
+
+void ViewSettings::setRowHeight(int height) {
+ if(height>=15) this->rowHeight = height;
+}
+
+void ViewSettings::setSearchName(QString searchName) {
+ this->searchName = searchName;
+}
+
+QString ViewSettings::getSearchName() {
+ return this->searchName;
+}
+
+std::map< OTF2_StringRef, std::pair>>>>* ViewSettings::getRankThreadMap() {
+ return &rankThreadMap;
+}
+
+std::map< OTF2_StringRef, otf2::definition::location_group *>* ViewSettings::getRankAdrMap() {
+ return &rankAdrMap;
+}
+
+QIcon* ViewSettings::getIcon(std::string key) {
+ return &Icons_.at(key);
+}
+
+int ViewSettings::getFlamegraphRankRef() {
+ return this->rankRef;
+}
+
+void ViewSettings::setFlamegraphRankRef(int newRankRef) {
+ this->rankRef = newRankRef;
+}
+
+
+void ViewSettings::setCountIndicatorsREG(bool newState) {
+ this->countIndicatorsREG = newState;
+}
+
+void ViewSettings::setCountIndicatorsP2P(bool newState) {
+ this->countIndicatorsP2P = newState;
+}
+
+void ViewSettings::setCountIndicatorsCCM(bool newState) {
+ this->countIndicatorsCCM = newState;
+}
+
+void ViewSettings::setCountIndicatorDetailsFlamegraph(bool newState) {
+ this->countIndicatorDetailsFlamegraph = newState;
+}
+
+void ViewSettings::setPxThresholdFlamegraph(bool newState) {
+ this->pxThresholdFlamegraph = newState;
+}
+
+void ViewSettings::setUseRealWidthFlamegraph(bool newState) {
+ this->useRealWidthFlamegraph = newState;
+}
+
+void ViewSettings::setUseRealWidthMainWindow(bool newState) {
+ this->useRealWidthMainWindow = newState;
+}
+
+void ViewSettings::setUseBorderOverview(bool newState) {
+ this->useBorderOverview = newState;
+}
+
+void ViewSettings::setUsePriorityOverview(bool newState) {
+ this->usePriorityOverview = newState;
+}
+
+void ViewSettings::setColorCodingTimeRecords(bool newState) {
+ this->colorCodingTimeRecords = newState;
+}
+
+void ViewSettings::setAbsoluteDurationsForSliders(bool newState) {
+ this->absoluteDurationsForSliders = newState;
+}
+
+void ViewSettings::setUseREGSliderForOV(bool newState) {
+ this->useREGSliderForOV = newState;
+}
+
+void ViewSettings::setActiveThresholdOV(double newVal) {
+ this->activeThresholdOV = newVal;
+}
+
+void ViewSettings::setActiveThresholdREG(double newVal) {
+ this->activeThresholdREG = newVal;
+}
+
+void ViewSettings::setActiveThresholdP2P(double newVal) {
+ this->activeThresholdP2P = newVal;
+}
+
+void ViewSettings::setActiveThresholdCCM(double newVal) {
+ this->activeThresholdCCM = newVal;
+}
+
+bool ViewSettings::getCountIndicatorsREG() {
+ return this->countIndicatorsREG;
+}
+
+bool ViewSettings::getCountIndicatorsP2P() {
+ return this->countIndicatorsP2P;
+}
+
+bool ViewSettings::getCountIndicatorsCCM() {
+ return this->countIndicatorsCCM;
+}
+
+bool ViewSettings::getCountIndicatorDetailsFlamegraph() {
+ return this->countIndicatorDetailsFlamegraph;
+}
+
+bool ViewSettings::getPxThresholdFlamegraph() {
+ return this->pxThresholdFlamegraph;
+}
+
+bool ViewSettings::getUseRealWidthFlamegraph() {
+ return this->useRealWidthFlamegraph;
+}
+
+bool ViewSettings::getUseRealWidthMainWindow() {
+ return this->useRealWidthMainWindow;
+}
+
+bool ViewSettings::getUseBorderOverview() {
+ return this->useBorderOverview;
+}
+
+bool ViewSettings::getUsePriorityOverview() {
+ return this->usePriorityOverview;
+}
+
+bool ViewSettings::getColorCodingTimeRecords() {
+ return this->colorCodingTimeRecords;
+}
+
+bool ViewSettings::getAbsoluteDurationsForSliders() {
+ return this->absoluteDurationsForSliders;
+}
+
+bool ViewSettings::getUseREGSliderForOV() {
+ return this->useREGSliderForOV;
+}
+
+double ViewSettings::getActiveThresholdOV() {
+ return this->activeThresholdOV;
+}
+
+double ViewSettings::getActiveThresholdREG() {
+ return this->activeThresholdREG;
+}
+
+double ViewSettings::getActiveThresholdP2P() {
+ return this->activeThresholdP2P;
+}
+
+double ViewSettings::getActiveThresholdCCM() {
+ return this->activeThresholdCCM;
+}
\ No newline at end of file
diff --git a/src/models/ViewSettings.hpp b/src/models/ViewSettings.hpp
index 1b54ceb..139d161 100644
--- a/src/models/ViewSettings.hpp
+++ b/src/models/ViewSettings.hpp
@@ -1,6 +1,9 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Florian Gallrein,
+ * Björn Gehrke,
+ * Jessica Lafontaine,
+ * Tomas Cirkov
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +24,12 @@
#include "src/models/Slot.hpp"
#include "Filter.hpp"
+#include
+#include
+#include
+
#define SETTINGS_DEFAULT_ZOOM_QUOTIENT 25
+#define SETTINGS_DEFAULT_ROW_HEIGHT 30
/**
* @brief The ViewSettings class encapsulates settings for the main view.
@@ -31,6 +39,7 @@
*/
class ViewSettings {
public:
+ static ViewSettings* getInstance();
/**
* @brief Returns the current filter.
@@ -63,7 +72,67 @@ class ViewSettings {
*/
void setZoomFactor(int zoomFactor);
+ int getRowHeight();
+
+ void setRowHeight(int height);
+
+ void setSearchName(QString name);
+
+ QString getSearchName();
+
+ std::map< OTF2_StringRef, std::pair>>>>* getRankThreadMap();
+
+ std::map< OTF2_StringRef, otf2::definition::location_group*>* getRankAdrMap();
+
+ QIcon* getIcon(std::string key);
+
+ int getFlamegraphRankRef();
+
+ void setFlamegraphRankRef(int rankRef);
+
+ void setCountIndicatorsREG(bool newState);
+ void setCountIndicatorsP2P(bool newState);
+ void setCountIndicatorsCCM(bool newState);
+ void setCountIndicatorDetailsFlamegraph(bool newState);
+ void setPxThresholdFlamegraph(bool newState);
+ void setUseRealWidthFlamegraph(bool newState);
+ void setUseRealWidthMainWindow(bool newState);
+ void setUseBorderOverview(bool newState);
+ void setUsePriorityOverview(bool newState);
+ void setColorCodingTimeRecords(bool newState);
+ void setAbsoluteDurationsForSliders(bool newState);
+ void setUseREGSliderForOV(bool newState);
+
+ void setActiveThresholdOV(double newVal);
+ void setActiveThresholdREG(double newVal);
+ void setActiveThresholdP2P(double newVal);
+ void setActiveThresholdCCM(double newVal);
+
+ bool getCountIndicatorsREG();
+ bool getCountIndicatorsP2P();
+ bool getCountIndicatorsCCM();
+ bool getCountIndicatorDetailsFlamegraph();
+ bool getPxThresholdFlamegraph();
+ bool getUseRealWidthFlamegraph();
+ bool getUseRealWidthMainWindow();
+ bool getUseBorderOverview();
+ bool getUsePriorityOverview();
+ bool getColorCodingTimeRecords();
+ bool getAbsoluteDurationsForSliders();
+ bool getUseREGSliderForOV();
+
+ double getActiveThresholdOV();
+ double getActiveThresholdREG();
+ double getActiveThresholdP2P();
+ double getActiveThresholdCCM();
+
+ QString globalMessage;
+
private:
+ static ViewSettings* instance;
+ ViewSettings();
+ ViewSettings(const ViewSettings& obj) = delete;
+
/**
* Backing field for the current zoom factor.
*/
@@ -72,6 +141,50 @@ class ViewSettings {
* Backing field for the current filter.
* */
Filter filter_;
+
+ int rowHeight = SETTINGS_DEFAULT_ROW_HEIGHT;
+
+ std::map< OTF2_StringRef, std::pair>>>> rankThreadMap{};
+
+ std::map< OTF2_StringRef, otf2::definition::location_group *> rankAdrMap{};
+
+ QString searchName = "";
+
+ QString executablePath = QCoreApplication::applicationDirPath();
+
+ std::map Icons_ {
+ {std::pair{"plus", ":/res/buttons/plus.png"}},
+ {std::pair{"plus_grey", ":/res/buttons/plus_grey.png"}},
+ {std::pair{"minus", ":/res/buttons/minus.png"}},
+ {std::pair{"zoom_in", ":/res/buttons/zoom_in.png"}},
+ {std::pair{"zoom_out", ":/res/buttons/zoom_out.png"}},
+ {std::pair{"zoom_fit", ":/res/buttons/zoom_fit.png"}},
+ {std::pair{"search", ":/res/buttons/search.png"}},
+ {std::pair{"book", ":/res/buttons/book.png"}},
+ {std::pair{"refresh", ":/res/buttons/refresh.png"}},
+ {std::pair{"maximize", ":/res/buttons/maximize.png"}}
+ };
+
+ int rankRef;
+
+ bool countIndicatorsREG=false;
+ bool countIndicatorsP2P=false;
+ bool countIndicatorsCCM=false;
+ bool countIndicatorDetailsFlamegraph=true;
+ bool pxThresholdFlamegraph=true;
+ bool useRealWidthFlamegraph=true;
+ bool useRealWidthMainWindow=false;
+
+ bool useBorderOverview=true;
+ bool usePriorityOverview=true;
+ bool colorCodingTimeRecords=true;
+ bool absoluteDurationsForSliders=true;
+ bool useREGSliderForOV=false;
+
+ double activeThresholdOV=0;
+ double activeThresholdREG=0;
+ double activeThresholdP2P=0;
+ double activeThresholdCCM=0;
};
diff --git a/src/models/communication/CollectiveCommunicationEvent.cpp b/src/models/communication/CollectiveCommunicationEvent.cpp
index d6cd685..6e74a9a 100644
--- a/src/models/communication/CollectiveCommunicationEvent.cpp
+++ b/src/models/communication/CollectiveCommunicationEvent.cpp
@@ -49,7 +49,18 @@ types::communicator * CollectiveCommunicationEvent::getCommunicator() const {
}
CommunicationKind CollectiveCommunicationEvent::getKind() const {
- return Collective;
+ switch(operation){
+ case otf2::collective_type::barrier:
+ case otf2::collective_type::all_gather:
+ case otf2::collective_type::all_gatherv:
+ case otf2::collective_type::all_to_all:
+ case otf2::collective_type::all_to_allv:
+ case otf2::collective_type::all_to_allw:
+ case otf2::collective_type::all_reduce:
+ return Synchronizing;
+ default:
+ return Collective;
+ }
}
otf2::collective_type CollectiveCommunicationEvent::getOperation() const {
diff --git a/src/models/communication/CommunicationKind.hpp b/src/models/communication/CommunicationKind.hpp
index 64fe886..df45062 100644
--- a/src/models/communication/CommunicationKind.hpp
+++ b/src/models/communication/CommunicationKind.hpp
@@ -29,31 +29,45 @@ enum CommunicationKind {
/**
* The communication event was a blocking send operation (e.g. MPI_SSEND)
*/
- BlockingSend,
+ BlockingSend = 1 << 0,
/**
* The communication event was a blocking receive operation (e.g. MPI_SRECEIVE)
*/
- BlockingReceive,
+ BlockingReceive = 1 << 1,
/**
* The communication event was a non blocking send operation (e.g. MPI_ISEND)
*/
- NonBlockingSend,
+ NonBlockingSend = 1 << 2,
/**
* The communication event was a non blocking receive operation (e.g. MPI_IRECEIVE)
*/
- NonBlockingReceive,
+ NonBlockingReceive = 1 << 3,
+
+ /**
+ * The communication event was a synchronizing and collective operation (e.g. MPI_BARRIER)
+ */
+ Synchronizing = 1 << 4,
/**
* The communication event was a collective operation (e.g. MPI_REDUCE)
*/
- Collective,
+ Collective = (1 << 5 | Synchronizing),
/**
* The communication event was a cancellation event (e.g. MPI_REQUEST_CANCEL)
*/
- RequestCancelled
+ RequestCancelled = 1 << 6,
+
+ /**
+ * The communication event was a Point to Point operation
+ */
+ PointToPoint = (BlockingSend | BlockingReceive | NonBlockingReceive | NonBlockingSend),
+
+ BlockingPointToPoint = (BlockingSend | BlockingReceive),
+
+ NonBlockingPointToPoint = (NonBlockingReceive | NonBlockingSend)
};
#endif //MOTIV_COMMUNICATIONKIND_HPP
diff --git a/src/models/mpianalysis/Node.cpp b/src/models/mpianalysis/Node.cpp
new file mode 100644
index 0000000..2a6cb9a
--- /dev/null
+++ b/src/models/mpianalysis/Node.cpp
@@ -0,0 +1,137 @@
+/*
+ * Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
+ * Copyright (C) 2024 Jessica Lafontaine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+
+#include "Node.hpp"
+
+Node::Node(Slot* slot): slot(slot){
+}
+
+bool Node::hasCommunication(){
+ if(communication == nullptr) return false;
+ else return true;
+}
+
+bool Node::hasCollectiveCommunication(){
+ if(collectiveCommunication == nullptr) return false;
+ else return true;
+}
+
+void Node::setCommunication(const Communication *comm){
+ this->communication = comm;
+}
+
+void Node::setCollectiveCommunication(const CollectiveCommunicationEvent *collectiveCommunication){
+ this->collectiveCommunication = collectiveCommunication;
+}
+
+void Node::addConnectedNode(Node* node){
+ // this->connectedNodes[node->getLocation()] = node;
+ this->connectedNodes[node->getLocation()].push_back(node);
+}
+
+void Node::addConnectedNode(uint16_t location, std::vector nodes){
+ this->connectedNodes[location] = nodes;
+}
+
+ void Node::addConnectedNode(std::vector nodes){
+ for(auto node : nodes){
+ if(node!=this) this->connectedNodes[node->getLocation()].push_back(node);
+ }
+
+ }
+
+Slot* Node::getSlot(){
+ return slot;
+}
+
+uint64_t Node::getLocation(){
+ return this->slot->location->ref();
+}
+
+otf2::definition::string Node::getRegionName(){
+ return slot->region->name();
+}
+
+const Communication* Node::getCommunication(){
+ if(this->hasCommunication()) return this->communication;
+ else throw std::runtime_error("No communication present");
+}
+
+const CollectiveCommunicationEvent* Node::getCollectiveCommunication(){
+ if(this->hasCollectiveCommunication()) return this->collectiveCommunication;
+ else{
+ throw std::runtime_error("No collective communication present");
+ }
+}
+
+CommunicationKind Node::getCommunicationKind(){
+ if(this->hasCommunication()) return this->getOwnEvent()->getKind();
+ else if(this->hasCollectiveCommunication()) return this->collectiveCommunication->getKind();
+ else throw std::runtime_error("No communication present");
+}
+
+std::map>& Node::getConnectedNodes(){
+ if(!connectedNodes.empty()) return connectedNodes;
+ else throw std::runtime_error("connectedNodes vector is empty");
+}
+
+uint64_t Node::getConnectedCommunicationRank(){
+ if(!this->hasCommunication()) throw std::runtime_error("No p2p communication present");
+ else if(communication->getStartEvent()->getLocation()->ref() != this->getLocation()) return communication->getStartEvent()->getLocation()->ref();
+ else return communication->getEndEvent()->getLocation()->ref();
+}
+
+const CommunicationEvent* Node::getOwnEvent(){
+ if(!this->hasCommunication()) throw std::runtime_error("No p2p communication present");
+ else if(communication->getStartEvent()->getLocation()->ref() == this->getLocation()) return communication->getStartEvent();
+ else return communication->getEndEvent();
+}
+
+const CommunicationEvent* Node::getConnectedEvent(){
+ if(!this->hasCommunication()) throw std::runtime_error("No p2p communication present");
+ else if(communication->getStartEvent()->getLocation()->ref() != this->getLocation()) return communication->getStartEvent();
+ else return communication->getEndEvent();
+}
+
+// void Node::setColor(){
+// std::string str = this->slot->region->name().str();
+// if(communication != nullptr || collectiveCommunication != nullptr) {
+// if((this->getCommunicationKind() & CommunicationKind::BlockingPointToPoint) ||
+// (this->getCommunicationKind() == CommunicationKind::Synchronizing)) this->color = Qt::red;
+// else this->color = Qt::blue;
+// }else {
+// QString regionName = QString::fromStdString(this->slot->region->name().str());
+// QString pattern = "(.*)(wait|probe|test)(.*)";
+// QRegularExpression regex(pattern, QRegularExpression::CaseInsensitiveOption);
+
+// if(regex.match(regionName).hasMatch()) this->color = Qt::darkGray;
+// else this->color = Qt::blue;
+// }
+// }
+
+// QColor Node::getColor(){
+// return this->color;
+// }
+
+bool Node::operator<(const Node& other) const {
+ return slot->endTime < other.slot->endTime;
+}
\ No newline at end of file
diff --git a/src/models/mpianalysis/Node.hpp b/src/models/mpianalysis/Node.hpp
new file mode 100644
index 0000000..8d1431f
--- /dev/null
+++ b/src/models/mpianalysis/Node.hpp
@@ -0,0 +1,82 @@
+/*
+ * Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
+ * Copyright (C) 2024 Jessica Lafontaine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef MOTIV_NODE_HPP
+#define MOTIV_NODE_HPP
+
+#include
+
+#include "src/models/communication/CollectiveCommunicationEvent.hpp"
+#include "src/models/communication/Communication.hpp"
+#include "src/models/Slot.hpp"
+
+class Node {
+public:
+ Node(Slot* slot);
+
+public: //methods
+
+// Slot related functions
+Slot* getSlot();
+uint64_t getLocation();
+otf2::definition::string getRegionName();
+
+
+// Communication related functions
+bool hasCommunication();
+bool hasCollectiveCommunication();
+
+void setCommunication(const Communication *communication);
+void setCollectiveCommunication(const CollectiveCommunicationEvent *collectiveCommunication);
+
+const Communication* getCommunication();
+const CollectiveCommunicationEvent* getCollectiveCommunication();
+CommunicationKind getCommunicationKind();
+
+// only for Nodes with P2P communication
+uint64_t getConnectedCommunicationRank();
+const CommunicationEvent* getOwnEvent();
+const CommunicationEvent* getConnectedEvent();
+
+
+// Node related functions
+void addConnectedNode(Node* node);
+void addConnectedNode(uint16_t location, std::vector nodes);
+void addConnectedNode(std::vector nodes);
+
+// void setColor();
+// QColor getColor();
+
+std::map>& getConnectedNodes();
+
+// Custom comparison operator to sort Node objects in ascending order of endTime
+bool operator<(const Node& other) const;
+
+private: //data
+ Slot *slot;
+ // QColor color;
+
+ std::map> connectedNodes;
+
+ const Communication *communication = nullptr;
+
+ // Exists only for collective communication Nodes
+ const CollectiveCommunicationEvent *collectiveCommunication = nullptr;
+};
+
+#endif //MOTIV_NODE_HPP
\ No newline at end of file
diff --git a/src/ui/ColorGenerator.cpp b/src/ui/ColorGenerator.cpp
index 6850d1e..ef720e9 100644
--- a/src/ui/ColorGenerator.cpp
+++ b/src/ui/ColorGenerator.cpp
@@ -1,6 +1,6 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Jessica Lafontaine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
#include "src/ui/Constants.hpp"
// Increment value for color updates, controls color diversity
-constexpr int COLOR_INCREMENT = 50;
+constexpr int COLOR_INCREMENT = 30;
// Minimum value for color components, controls color saturation
int MIN = 50;
@@ -27,7 +27,7 @@ int MIN = 50;
// Singleton instance
ColorGenerator* ColorGenerator::instance = nullptr_t();
-ColorGenerator::ColorGenerator():red{255}, green {0}, blue{50}, min{MIN}, token {0}
+ColorGenerator::ColorGenerator():red{255}, green {MIN}, blue{MIN}, min{MIN}, token {0}
{
}
@@ -38,16 +38,19 @@ ColorGenerator* ColorGenerator::getInstance()
}
// Update color value based on comparison color
-int ColorGenerator::updateColor(int color, int comparison_color){
- if (token == 2 && this->red > 249 && this->greenbluemin+=COLOR_INCREMENT;
- else{
- this->red=189;
- this->green=189;
- this->blue=189;
- this->token = 3;
- return 189;
- }
+int ColorGenerator::updateColor(int color, int comparison_color){
+ if (token == 4 || (token == 2 && this->red == 255 && this->green >= min-COLOR_INCREMENT && this->blue == min)){
+ if(min<255-2*COLOR_INCREMENT) {
+ this->min+=COLOR_INCREMENT;
+ return color-=COLOR_INCREMENT;
+ }
+ else{
+ this->red=250;
+ this->green=250;
+ this->blue=250;
+ this->token = 4;
+ return 250;
+ }
}
@@ -60,7 +63,7 @@ if (comparison_color==min){
}
}else{
- if ((color-COLOR_INCREMENT)>min-1) return color-=COLOR_INCREMENT;
+ if ((color-COLOR_INCREMENT)>=min) return color-=COLOR_INCREMENT;
else{
this->token = (token +1)%3;
return min;
@@ -73,30 +76,27 @@ if (comparison_color==min){
QColor ColorGenerator::GetNewColor(){
QColor color;
switch(token){
- // Update red value
+ // Update red value
case 1:
color = QColor(red,green,blue);
this->red=updateColor(red,blue);
- if(token == 2) this->green=updateColor(green,red);
break;
- // Update green value
+ // Update green value
case 2:
color = QColor(red,green,blue);
this->green=updateColor(green,red);
- if(token==0) this->blue=updateColor(blue,green);
break;
// Update blue value
case 0:
color = QColor(red,green,blue);
- this->blue = updateColor(blue,green);
- if(token==1) this->red=updateColor(red,blue);
+ this->blue = updateColor(blue,green);
break;
- default:
- color = colors::COLOR_SLOT_PLAIN;
+ default:
+ color = QColor::fromRgb(0xFAFAFA);
break;
}
return color;
@@ -105,8 +105,8 @@ QColor ColorGenerator::GetNewColor(){
void ColorGenerator::setDefault(){
this->red=255;
- this->green=0;
- this->blue=50;
+ this->green=MIN;
+ this->blue=MIN;
this->min=MIN;
this->token=0;
}
diff --git a/src/ui/ColorGenerator.hpp b/src/ui/ColorGenerator.hpp
index a5dac1a..f0e38c5 100644
--- a/src/ui/ColorGenerator.hpp
+++ b/src/ui/ColorGenerator.hpp
@@ -1,6 +1,6 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Jessica Lafontaine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/ui/ColorSynchronizer.cpp b/src/ui/ColorSynchronizer.cpp
index 1c12370..fd7ceeb 100644
--- a/src/ui/ColorSynchronizer.cpp
+++ b/src/ui/ColorSynchronizer.cpp
@@ -1,6 +1,6 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Jessica Lafontaine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@ void ColorSynchronizer::synchronizeColors(const std::string& function, const QCo
if(slot->region->name().str()==function) slot->setColor(color);
}
}
- data_->colorChanged();
+ Q_EMIT data_->colorChanged();
}
void ColorSynchronizer::synchronizeColors(const QColor& color, bool all){
@@ -55,7 +55,7 @@ void ColorSynchronizer::synchronizeColors(const QColor& color, bool all){
}
}
}
- data_->colorChanged();
+ Q_EMIT data_->colorChanged();
}
@@ -69,7 +69,7 @@ void ColorSynchronizer::synchronizeColors(){
slot->setColor(map->getColor(function_));
}
}
- data_->colorChanged();
+ Q_EMIT data_->colorChanged();
}
void ColorSynchronizer::reCalculateColors(){
@@ -100,7 +100,7 @@ void ColorSynchronizer::reCalculateColors(){
}
}
}
- data_->colorChanged();
+ Q_EMIT data_->colorChanged();
}
diff --git a/src/ui/ColorSynchronizer.hpp b/src/ui/ColorSynchronizer.hpp
index 8e3d37d..297b129 100644
--- a/src/ui/ColorSynchronizer.hpp
+++ b/src/ui/ColorSynchronizer.hpp
@@ -1,6 +1,6 @@
/*
* Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
- * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
+ * Copyright (C) 2023 Jessica Lafontaine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/ui/ScrollSynchronizer.cpp b/src/ui/ScrollSynchronizer.cpp
index 5a19651..ec7eb3b 100644
--- a/src/ui/ScrollSynchronizer.cpp
+++ b/src/ui/ScrollSynchronizer.cpp
@@ -20,7 +20,6 @@
#include
ScrollSynchronizer::ScrollSynchronizer(QObject *parent) : QObject(parent) {
-
}
void ScrollSynchronizer::addWidget(QAbstractScrollArea *newWidget) {
@@ -28,8 +27,9 @@ void ScrollSynchronizer::addWidget(QAbstractScrollArea *newWidget) {
return;
}
for (const auto &widget : this->widgets) {
+ // Classic
connect(widget->verticalScrollBar(), &QScrollBar::valueChanged, newWidget->verticalScrollBar(), &QScrollBar::setValue);
connect(newWidget->verticalScrollBar(), &QScrollBar::valueChanged, widget->verticalScrollBar(), &QScrollBar::setValue);
}
this->widgets.push_back(newWidget);
-}
+}
\ No newline at end of file
diff --git a/src/ui/TraceDataProxy.cpp b/src/ui/TraceDataProxy.cpp
index 888d3ed..b77f963 100644
--- a/src/ui/TraceDataProxy.cpp
+++ b/src/ui/TraceDataProxy.cpp
@@ -54,7 +54,6 @@ ViewSettings *TraceDataProxy::getSettings() const {
return settings;
}
-
types::TraceTime TraceDataProxy::getTotalRuntime() const {
return trace->getRuntime();
}
diff --git a/src/ui/TraceDataProxy.hpp b/src/ui/TraceDataProxy.hpp
index e80d866..5a24697 100644
--- a/src/ui/TraceDataProxy.hpp
+++ b/src/ui/TraceDataProxy.hpp
@@ -115,6 +115,19 @@ public: Q_SIGNALS:
*/
void filterChanged(Filter);
+ void verticalZoomChanged();
+
+ void refreshOverviewRequest();
+
+ void refreshButtonPressed();
+
+ void flamegraphRequest();
+
+ void hideSlidersBoxRequest();
+
+ void triggerUITimerStartIfPossible();
+ void triggerUITimerEndIfPossible();
+
public Q_SLOTS:
/**
* Change the start time of the selection
diff --git a/src/ui/views/FlamegraphView.cpp b/src/ui/views/FlamegraphView.cpp
new file mode 100644
index 0000000..b72fca9
--- /dev/null
+++ b/src/ui/views/FlamegraphView.cpp
@@ -0,0 +1,320 @@
+/*
+ * Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
+ * Copyright (C) 2023 Tomas Cirkov
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "TimelineView.hpp"
+#include "FlamegraphView.hpp"
+#include "src/models/ViewSettings.hpp"
+#include "src/ui/views/CommunicationIndicator.hpp"
+#include "src/ui/views/SlotIndicator.hpp"
+#include "src/ui/Constants.hpp"
+#include "CollectiveCommunicationIndicator.hpp"
+#include "src/ui/ColorGenerator.hpp"
+
+#include