Project
Loading...
Searching...
No Matches
FrameworkGUIDataRelayerUsage.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11#include "DebugGUI/imgui.h"
12#include <functional>
18#include "InspectorHelpers.h"
19#include "PaletteHelpers.h"
21#include <cstring>
22#include <cmath>
23
24static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
25static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }
26
28{
29// This is to display the information in the data relayer
31 template <typename RECORD, typename ITEM>
32 static void draw(const char* /*name*/,
33 int& v,
34 ImVec2 const& sizeHint,
35 std::function<size_t()> const& getNumInputs,
36 std::function<size_t()> const& getNumRecords,
37 std::function<RECORD(size_t)> const& getRecord,
38 std::function<size_t(RECORD const&)> const& getNumItems,
39 std::function<ITEM const*(RECORD const&, size_t)> const& getItem,
40 std::function<int(ITEM const&)> const& getValue,
41 std::function<ImU32(int value)> const& getColor,
42 std::function<void(int row, int column)> const& describeCell)
43 {
44 float padding = 1;
45 // add slider to scroll between the grid display windows
46 size_t nw = getNumRecords() < WND ? 1 : getNumRecords() / WND;
47 ImGui::PushItemWidth(sizeHint.x);
48 ImGui::SliderInt("##window", &v, 1, nw, "wnd: %d", ImGuiSliderFlags_AlwaysClamp);
49 ImVec2 sliderMin = ImGui::GetItemRectMin();
50
51 constexpr float MAX_BOX_X_SIZE = 16.f;
52 constexpr float MAX_BOX_Y_SIZE = 16.f;
53
54 ImVec2 size = ImVec2(sizeHint.x, std::min(sizeHint.y, MAX_BOX_Y_SIZE * getNumInputs() + 2));
55 ImU32 BORDER_COLOR = ImColor(200, 200, 200, 255);
56 ImU32 BACKGROUND_COLOR = ImColor(20, 20, 20, 255);
57 ImU32 BORDER_COLOR_A = ImColor(200, 200, 200, 0);
58 ImU32 BACKGROUND_COLOR_A = ImColor(0, 0, 0, 0);
59
60 ImDrawList* drawList = ImGui::GetWindowDrawList();
61 ImVec2 winPos = sliderMin;
62
63 // overlay activity indicator on the slider
64 auto xsz = size.x / nw;
65 drawList->AddRectFilled(
66 ImVec2{0., 0.} + winPos,
67 ImVec2{size.x, size.y} + winPos,
68 BACKGROUND_COLOR_A);
69 drawList->AddRect(
70 ImVec2{0. - 1, -1} + winPos,
71 ImVec2{size.x + 1, size.y - 1} + winPos,
72 BORDER_COLOR_A);
73
74 const static auto colorA = ImColor(ImVec4{0.945, 0.096, 0.278, 0.5});
75 const static auto colorE = ImColor(ImVec4{0, 0, 0, 0});
76
77 drawList->PrimReserve(nw * 6, nw * 4);
78 for (size_t iw = 1; iw <= nw; ++iw) {
79 ImVec2 xOffset{(iw - 1) * xsz + 2 * padding, 0};
80 ImVec2 xSize{xsz - 2 * padding, 0};
81 ImVec2 yOffset{0, 2 * padding};
82 ImVec2 ySize{0, MAX_BOX_Y_SIZE - 4 * padding};
83 bool active = false;
84 for (size_t ir = (iw - 1) * WND; ir < ((iw * WND > getNumRecords()) ? getNumRecords() : iw * WND); ++ir) {
85 for (size_t i = 0; i < getNumItems(getRecord(ir)); ++i) {
86 active = getValue(*getItem(getRecord(ir), i)) > 0;
87 if (active) {
88 break;
89 }
90 }
91 if (active) {
92 break;
93 }
94 }
95 drawList->PrimRect(
96 xOffset + yOffset + winPos,
97 xOffset + xSize + yOffset + ySize + winPos,
98 active ? colorA : colorE);
99 }
100
101 // display the grid
102 auto boxSizeX = std::min(size.x / WND, MAX_BOX_X_SIZE);
103 auto boxSizeY = std::min(size.y / getNumInputs(), MAX_BOX_Y_SIZE);
104
105 winPos = ImGui::GetCursorScreenPos() + ImVec2{0, 7};
106 ImGui::InvisibleButton("sensitive area", ImVec2(size.x, size.y));
107 if (ImGui::IsItemHovered()) {
108 auto pos = ImGui::GetMousePos() - winPos;
109 auto slot = (v - 1) * WND + std::lround(std::trunc(pos.x / boxSizeX));
110 auto row = std::lround(std::trunc(pos.y / boxSizeY));
111 describeCell(row, slot);
112 }
113
114 // background
115 drawList->AddRectFilled(
116 ImVec2(0., 0.) + winPos,
117 ImVec2{size.x, size.y} + winPos,
118 BACKGROUND_COLOR);
119 // border
120 drawList->AddRect(
121 ImVec2(0. - 1, -1) + winPos,
122 ImVec2{size.x + 1, size.y - 1} + winPos,
123 BORDER_COLOR);
124
125 // heatmap
126 size_t totalPrims = WND * getNumInputs();
127 drawList->PrimReserve(totalPrims * 6, totalPrims * 4);
128 for (size_t ri = (v - 1) * WND; ri < (((size_t)(v)*WND > getNumRecords()) ? getNumRecords() : v * WND); ++ri) {
129 auto record = getRecord(ri);
130 ImVec2 xOffset{((float)(ri - (v - 1) * WND) * boxSizeX) + padding, 0};
131 ImVec2 xSize{boxSizeX - 2 * padding, 0};
132
133 for (auto mi = 0U; mi < getNumItems(record); mi++) {
134 ImVec2 yOffSet{0, ((float)mi * boxSizeY) + padding};
135 ImVec2 ySize{0, boxSizeY - 2 * padding};
136
137 ImVec2 A = xOffset + yOffSet + winPos;
138 ImVec2 B = xOffset + xSize + yOffSet + ySize + winPos;
139
140 drawList->PrimRect(
141 A, B,
142 getColor(getValue(*getItem(record, mi))));
143 }
144 }
145
146 ImGui::SetCursorScreenPos(winPos + size);
147 }
148};
149
150void displayDataRelayer(DeviceMetricsInfo const& /*metrics*/,
151 DeviceInfo const& /*info*/,
152 DeviceSpec const& spec,
154 ImVec2 const& size,
155 int& v)
156{
157 auto getNumInputs = [&states]() -> size_t {
158 auto& inputsView = states.statesViews[(int)ProcessingStateId::DATA_QUERIES];
159 std::string_view inputs(states.statesBuffer.data() + inputsView.first, inputsView.size);
160 if (inputs.size() == 0) {
161 return 0;
162 }
163 // count the number of semi-colon separators to get number of inputs
164 int numInputs = std::count(inputs.begin(), inputs.end(), ';');
165 return numInputs;
166 };
167 auto getNumRecords = [&states]() -> size_t {
168 auto& view = states.statesViews[(int)ProcessingStateId::DATA_RELAYER_BASE];
169 if (view.size == 0) {
170 return 0;
171 }
172 // The first number is the size of the pipeline
173 int numRecords = strtoul(states.statesBuffer.data() + view.first, nullptr, 10);
174 return numRecords;
175 };
176 auto getRecord = [](size_t i) -> int {
177 return i;
178 };
179 auto getNumItems = [&states](int record) -> int {
180 auto& view = states.statesViews[(int)ProcessingStateId::DATA_RELAYER_BASE + record];
181 if (view.size == 0) {
182 return 0;
183 }
184 char const* beginData = strchr(states.statesBuffer.data() + view.first, ' ') + 1;
185 // The number of elements is given by the size of the state, minus the header
186 int size = view.size - (beginData - (states.statesBuffer.data() + view.first));
187 return size;
188 };
189 auto getItem = [&states](int const& record, size_t i) -> int8_t const* {
190 static int8_t const zero = '0';
191 static int8_t const error = '4';
192 char const *buffer = states.statesBuffer.data();
193 auto& view = states.statesViews[(int)ProcessingStateId::DATA_RELAYER_BASE + record];
194 if (view.size == 0) {
195 return &zero;
196 }
197 char const* const beginData = strchr(buffer + view.first, ' ') + 1;
198 // Protect against buffer overflows
199 if ((size_t)view.size <= beginData - buffer + i - view.first) {
200 return &error;
201 }
202 return (int8_t const*)beginData + i; };
203 auto getValue = [](int8_t const& item) -> int { return item - '0'; };
204 auto getColor = [](int value) {
205 static const ImU32 SLOT_EMPTY = ImColor(70, 70, 70, 255);
206 static const ImU32 SLOT_FULL = ImColor(PaletteHelpers::RED);
207 static const ImU32 SLOT_DISPATCHED = ImColor(PaletteHelpers::YELLOW);
208 static const ImU32 SLOT_DONE = ImColor(PaletteHelpers::GREEN);
209 static const ImU32 SLOT_ERROR = ImColor(0xfe, 0x43, 0x65, 255);
210 switch (value) {
211 case 0:
212 return SLOT_EMPTY;
213 case 1:
214 return SLOT_FULL;
215 case 2:
216 return SLOT_DISPATCHED;
217 case 3:
218 return SLOT_DONE;
219 }
220 return SLOT_ERROR;
221 };
222 auto describeCell = [&states, &spec](int row, int slot) -> void {
223 ImGui::BeginTooltip();
224
225 // display the input (origin/descr/subspec)
226 auto& inputsView = states.statesViews[(int)ProcessingStateId::DATA_QUERIES];
227 std::string_view inputs(states.statesBuffer.data() + inputsView.first, inputsView.size);
228 auto beginInputs = inputs.begin();
229 auto endInputs = beginInputs + inputsView.size;
230 char const* input = beginInputs;
231 size_t i = 0;
232 while (input != endInputs) {
233 auto end = std::find(input, endInputs, ';');
234 if ((end - input) == 0) {
235 continue;
236 }
237 if (i == (size_t)row) {
238 ImGui::Text("%d %.*s (%s)", row, int(end - input), input, InspectorHelpers::getLifeTimeStr(spec.inputs[i].matcher.lifetime));
239 break;
240 }
241 ++i;
242 input = end + 1;
243 }
244
245 // display context variables
246 ImGui::Text("Input query matched values for slot: %d", slot);
247 auto& view = states.statesViews[(short)ProcessingStateId::CONTEXT_VARIABLES_BASE + (short)slot];
248 auto begin = view.first;
249 for (size_t vi = 0; vi < data_matcher::MAX_MATCHING_VARIABLE; ++vi) {
250 std::string_view state(states.statesBuffer.data() + begin, view.size);
251 // find the semi-colon, which separates entries in the variable list
252 auto pos = state.find(';');
253 std::string_view value = state.substr(0, pos);
254 // Do not display empty values.
255 if (value.empty()) {
256 begin += 1;
257 continue;
258 }
259 switch (vi) {
261 ImGui::Text("$%zu (startTime): %.*s", vi, (int)value.size(), value.data());
262 break;
264 ImGui::Text("$%zu (tfCounter): %.*s", vi, (int)value.size(), value.data());
265 break;
267 ImGui::Text("$%zu (firstTForbit): %.*s", vi, (int)value.size(), value.data());
268 break;
269 default:
270 ImGui::Text("$%zu: %.*s", vi, (int)value.size(), value.data());
271 }
272 begin += pos + 1;
273 }
274 ImGui::EndTooltip();
275 };
276
277 if (getNumRecords()) {
278 HeatMapHelper::draw<int, int8_t>("DataRelayer",
279 v,
280 size,
281 getNumInputs,
282 getNumRecords,
283 getRecord,
284 getNumItems,
285 getItem,
286 getValue,
287 getColor,
288 describeCell);
289 }
290}
291
292} // namespace o2::framework::gui
benchmark::State & state
uint16_t padding
int32_t i
uint16_t pos
Definition RawData.h:3
Definition A.h:16
Definition B.h:16
GLuint buffer
Definition glcorearb.h:655
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
const GLdouble * v
Definition glcorearb.h:832
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLuint * states
Definition glcorearb.h:4932
@ FIRSTTFORBIT_POS
The DataHeader::tfCounter associated to the timeslice.
@ TFCOUNTER_POS
The DataProcessingHeader::startTime associated to the timeslice.
State for the main GUI window.
void displayDataRelayer(DeviceMetricsInfo const &, DeviceInfo const &, DeviceSpec const &spec, DataProcessingStates const &states, ImVec2 const &size, int &v)
View of the DataRelayer metrics for a given DeviceInfo.
D const SVectorGPU< T, D > & rhs
Definition SMatrixGPU.h:193
Vertex< T > operator-(const Vertex< T > &a, const Vertex< T > &b)
Definition Vertex.h:98
BinCenterView< AxisIterator > operator+(BinCenterView< AxisIterator > lhs, int n)
double getValue(DPVAL dp)
std::vector< InputRoute > inputs
Definition DeviceSpec.h:62
static const char * getLifeTimeStr(Lifetime lifetime)
static void draw(const char *, int &v, ImVec2 const &sizeHint, std::function< size_t()> const &getNumInputs, std::function< size_t()> const &getNumRecords, std::function< RECORD(size_t)> const &getRecord, std::function< size_t(RECORD const &)> const &getNumItems, std::function< ITEM const *(RECORD const &, size_t)> const &getItem, std::function< int(ITEM const &)> const &getValue, std::function< ImU32(int value)> const &getColor, std::function< void(int row, int column)> const &describeCell)
o2::InteractionRecord ir(0, 0)
std::vector< int > row