Motiv
Marvelous OTF2 Traces Interactive Visualizer
Loading...
Searching...
No Matches
UITrace.cpp
1/*
2 * Marvelous OTF2 Traces Interactive Visualizer (MOTIV)
3 * Copyright (C) 2023 Florian Gallrein, Björn Gehrke
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18#include "UITrace.hpp"
19#include "src/utils.hpp"
20
21#include <QDebug>
22
23UITrace::UITrace(std::map<otf2::definition::location_group *, std::vector<Slot *>, LocationGroupCmp> slotsVec,
24 const Range<Communication *> &communications,
25 const Range<CollectiveCommunicationEvent *> &collectiveCommunications,
26 const otf2::chrono::duration &runtime, const otf2::chrono::duration &startTime,
27 const otf2::chrono::duration &timePerPx) :
28 SubTrace(),
29 timePerPx_(timePerPx) {
30 communications_ = communications;
31 collectiveCommunications_ = collectiveCommunications;
32 runtime_ = runtime;
33 startTime_ = startTime;
34
35 for (auto &item: slotsVec) {
36 slots_.insert({item.first, Range(item.second)});
37 }
38}
40 return forResolution(trace, trace->getRuntime() / width);
41}
42
43UITrace *UITrace::forResolution(Trace *trace, otf2::chrono::duration timePerPixel) {
44
45 // Optimize slots
46 auto minDuration = timePerPixel * MIN_SLOT_SIZE_PX;
47 std::map<otf2::definition::location_group *, std::vector<Slot *>, LocationGroupCmp> newSlots;
48 for (const auto &item: trace->getSlots()) {
49 auto locationGroup = item.first;
50 auto slots = item.second;
51 auto newSlotsForRank = optimize<Slot, SlotKind>(
52 minDuration,
53 slots,
55 &UITrace::aggregateSlots);
56
57 newSlots.insert({locationGroup, newSlotsForRank});
58 }
59
60
61 // Optimize communications.
62 // Optimization is done per rank of the starting event. This is beneficial if few 1:n communications occur.
63 // 1:n communications are only visible with a higher zoom level.
64 minDuration = timePerPixel * MIN_COMMUNICATION_SIZE_PX;
65 auto communicationsByRank = groupBy<Communication *, otf2::reference<otf2::definition::location_group>>(
66 trace->getCommunications(),
67 [](const Communication *c) { return c->getStartEvent()->getLocation()->location_group().ref(); },
68 [](const Communication *l, const Communication *r) {
69 auto rankL = l->getStartEvent()->getLocation()->location_group().ref();
70 auto rankR = r->getStartEvent()->getLocation()->location_group().ref();
71
72 if (rankL == rankR) {
73 return l->getStartTime() < r->getStartTime();
74 }
75
76 return rankL < rankR;
77 });
78
79 std::vector<Communication *> newCommunications;
80 for (const auto &item: communicationsByRank) {
81 auto communications = item.second;
82 auto newCommunicationsForRank = optimize<Communication>(
83 minDuration,
84 communications,
85 [](Communication *starter, std::vector<Communication *> &) { return starter; });
86 newCommunications.insert(newCommunications.end(), newCommunicationsForRank.begin(),
87 newCommunicationsForRank.end());
88 }
89
90
91 // Optimize collective communications
92 minDuration = timePerPixel * MIN_COLLECTIVE_EVENT_SIZE_PX;
93 auto newCollectiveCommunications = optimize<CollectiveCommunicationEvent>(minDuration,
95 &UITrace::aggregateCollectiveCommunications);
96
97 return new UITrace(newSlots, Range(newCommunications), Range(newCollectiveCommunications),
98 trace->getRuntime(), trace->getStartTime(), timePerPixel);
99}
100
101template<class T>
102requires std::is_base_of_v<TimedElement, T>
103std::vector<T *> UITrace::optimize(types::TraceTime minDuration,
104 Range<T *> elements,
105 std::function<T *(T *, std::vector<T *> &stats)> aggregate) {
106 // This optimization implementation does not group elements in an interval. To not replicate code, it calls the
107 // overload that groups and groups all elements into a single group.
108 return optimize<T, uint8_t>(
109 minDuration,
110 elements,
111 [](const T *) { return 0; },
112 [aggregate](T *starter, std::map<uint8_t, std::vector<T *>> &stats) {
113 return aggregate(starter, stats[0]);
114 });
115}
116
117template<class T, typename K>
118requires std::is_base_of_v<TimedElement, T>
119std::vector<T *> UITrace::optimize(types::TraceTime minDuration,
120 Range<T *> &elements,
121 std::function<K(const T *)> keySelector,
122 std::function<T *(T *, std::map<K, std::vector<T *>> &stats)> aggregate) {
123 std::vector<T *> newElements;
124 T *intervalStarter = nullptr;
125 std::map<K, std::vector<T *>> stats;
126
127 for (const auto &element: elements) {
128 // Check whether the current element is outside the interval (start + minDuration). If so, group interval and continue.
129 if (intervalStarter != nullptr && (element->getStartTime() > intervalStarter->getStartTime() + minDuration)) {
130 newElements.push_back(aggregate(intervalStarter, stats));
131
132 stats.clear();
133 intervalStarter = nullptr;
134 }
135
136 // Check if element is too short
137 if (element->getDuration() < minDuration) {
138 if (intervalStarter == nullptr) {
139 intervalStarter = element;
140 }
141
142 // Insert element in group
143 if (!stats.contains(keySelector(element))) {
144 stats.insert({keySelector(element), std::vector<T *>()});
145 }
146
147 stats.at(keySelector(element)).push_back(element);
148 } else {
149 newElements.push_back(element);
150 }
151 }
152
153 // If the trace ends with a short interval it must be completed.
154 if (intervalStarter) {
155 newElements.push_back(aggregate(intervalStarter, stats));
156 }
157 return newElements;
158}
159
160template<class T>
161requires std::is_base_of_v<TimedElement, T>
162static T *longest(std::vector<T *> ls) {
163 return *std::max_element(ls.begin(), ls.end(), [](T *lhs, T *rhs) {
164 return lhs->getDuration() > rhs->getDuration();
165 });
166}
167
168template<class T>
169requires std::is_base_of_v<TimedElement, T>
170static T *last(std::vector<T *> ls) {
171 return *std::max_element(ls.begin(), ls.end(), [](T *lhs, T *rhs) {
172 return lhs->getEndTime() < rhs->getEndTime();
173 });
174}
175
176
177Slot *UITrace::aggregateSlots(const Slot *intervalStarter, std::map<SlotKind, std::vector<Slot *>> &stats) {
178 std::vector<Slot *>* elements;
179 // Order of importance if overlapping, the slot with the most important kind is shown.
180 // 1. MPI events, 2. OpenMP events 3. all other events
181 if (stats.contains(MPI)) {
182 elements = &stats.at(MPI);
183 } else if (stats.contains(OpenMP)) {
184 elements = &stats.at(OpenMP);
185 } else {
186 elements = &stats.at(Plain);
187 }
188
189 auto longestSlot = longest(*elements);
190 auto intervalEnder = last(*elements);
191
192 return new Slot(intervalStarter->startTime, intervalEnder->endTime, longestSlot->location, longestSlot->region);
193}
194
195CollectiveCommunicationEvent *UITrace::aggregateCollectiveCommunications(
196 const CollectiveCommunicationEvent *intervalStarter,
197 std::vector<CollectiveCommunicationEvent *> &stats) {
198 auto longestEvent = longest(stats);
199 auto intervalEnder = last(stats);
200
201 auto singleMember = new CollectiveCommunicationEvent::Member(intervalStarter->getStartTime(),
202 intervalEnder->getEndTime(),
203 longestEvent->getLocation());
204
205 std::vector<CollectiveCommunicationEvent::Member *> singletonMembers;
206 singletonMembers.push_back(singleMember);
207
209 singletonMembers, longestEvent->getLocation(), longestEvent->getCommunicator(),
210 longestEvent->getOperation(), longestEvent->getRoot()
211 );
212}
213
214Trace *UITrace::subtrace(otf2::chrono::duration from, otf2::chrono::duration to) {
215 return forResolution(SubTrace::subtrace(from, to), timePerPx_);
216}
A class representing a member of a collective operation.
A class representing an MPI collective operation.
otf2::chrono::duration getStartTime() const override
virtual otf2::definition::location * getLocation() const =0
Class representing any (successful or unsuccessful) communication.
const CommunicationEvent * getStartEvent() const
types::TraceTime getStartTime() const override
Returns the start time of the current object.
A custom range implementation around std::vector<T>s.
Definition: Range.hpp:37
A Slot represents a visual slot to be rendered in the UI. It contains the information of a location.
Definition: Slot.hpp:37
SlotKind getKind() const
Returns the kind of the current Slot object.
Definition: Slot.cpp:30
otf2::chrono::duration startTime
Start time of the slot relative to the trace start time.
Definition: Slot.hpp:55
Trace representing a section of a larger trace.
Definition: SubTrace.hpp:28
Trace * subtrace(otf2::chrono::duration from, otf2::chrono::duration to) override
Creates a subtrace of the current trace.
Definition: SubTrace.cpp:93
virtual types::TraceTime getStartTime() const =0
Returns the start time of the current object.
Abstract base class for a trace.
Definition: Trace.hpp:52
virtual otf2::chrono::duration getRuntime() const =0
Returns the runtime of the current trace.
virtual std::map< otf2::definition::location_group *, Range< Slot * >, LocationGroupCmp > getSlots() const =0
Returns a map of slots of the current trace.
virtual Range< CollectiveCommunicationEvent * > getCollectiveCommunications()=0
Returns collective communication events of the current trace.
virtual Range< Communication * > getCommunications()=0
Returns communication objects of the current trace.
Trace facilitating a subtrace optimized for rendering.
Definition: UITrace.hpp:48
Trace * subtrace(otf2::chrono::duration from, otf2::chrono::duration to) override
Creates a subtrace of the current trace.
Definition: UITrace.cpp:214
static UITrace * forResolution(Trace *trace, otf2::chrono::duration timePerPixel)
Definition: UITrace.cpp:43
A comparator for otf2::definition::location_group objects.
Definition: Trace.hpp:34