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"
20#include "Framework/Logger.h"
21#include <iostream>
22#include <cstring>
23#include <cmath>
24
25static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
26static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }
27
29{
30
31// This is to display the information in the data relayer
33 template <typename RECORD, typename ITEM>
34 static void draw(const char* name,
35 ImVec2 const& sizeHint,
36 std::function<size_t()> const& getNumInputs,
37 std::function<size_t()> const& getNumRecords,
38 std::function<RECORD(size_t)> const& getRecord,
39 std::function<size_t(RECORD const&)> const& getNumItems,
40 std::function<ITEM const*(RECORD const&, size_t)> const& getItem,
41 std::function<int(ITEM const&)> const& getValue,
42 std::function<ImU32(int value)> const& getColor,
43 std::function<void(int row, int column)> const& describeCell)
44 {
45 ImVec2 size = ImVec2(sizeHint.x, std::min(sizeHint.y, 16.f * getNumItems(0) + 2));
46 ImU32 BORDER_COLOR = ImColor(200, 200, 200, 255);
47 ImU32 BACKGROUND_COLOR = ImColor(20, 20, 20, 255);
48 constexpr float MAX_BOX_X_SIZE = 16.f;
49 constexpr float MAX_BOX_Y_SIZE = 16.f;
50 ImDrawList* drawList = ImGui::GetWindowDrawList();
51 ImVec2 winPos = ImGui::GetCursorScreenPos() + ImVec2{0, 7};
52 auto records = getNumRecords();
53 auto boxSizeX = std::min(size.x / records, MAX_BOX_X_SIZE);
54 auto numInputs = getNumInputs();
55
56 ImGui::InvisibleButton("sensible area", ImVec2(size.x, size.y));
57 if (ImGui::IsItemHovered()) {
58 auto pos = ImGui::GetMousePos() - winPos;
59 auto slot = std::lround(std::trunc(pos.x / size.x * records));
60 auto row = std::lround(std::trunc(pos.y / size.y * numInputs));
61 describeCell(row, slot);
62 }
63
64 drawList->AddRectFilled(
65 ImVec2(0., 0.) + winPos,
66 ImVec2{size.x, size.y} + winPos,
67 BACKGROUND_COLOR);
68 drawList->AddRect(
69 ImVec2(0. - 1, -1) + winPos,
70 ImVec2{size.x + 1, size.y - 1} + winPos,
71 BORDER_COLOR);
72 float padding = 1;
73
74 size_t totalRects = 0;
75 for (size_t ri = 0, re = getNumRecords(); ri < re; ri++) {
76 auto record = getRecord(ri);
77 totalRects += getNumItems(record);
78 }
79
80 drawList->PrimReserve(totalRects * 6, totalRects * 4);
81 for (size_t ri = 0, re = getNumRecords(); ri < re; ri++) {
82 auto record = getRecord(ri);
83 ImVec2 xOffset{(ri * boxSizeX) + padding, 0};
84 ImVec2 xSize{boxSizeX - 2 * padding, 0};
85 auto boxSizeY = std::min(size.y / getNumItems(record), MAX_BOX_Y_SIZE);
86 for (size_t mi = 0, me = getNumItems(record); mi < me; mi++) {
87 ImVec2 yOffSet{0, (mi * boxSizeY) + padding};
88 ImVec2 ySize{0, boxSizeY - 2 * padding};
89
90 drawList->PrimRect(
91 xOffset + yOffSet + winPos,
92 xOffset + xSize + yOffSet + ySize + winPos,
93 getColor(getValue(*getItem(record, mi))));
94 }
95 }
96
97 ImGui::SetCursorScreenPos(winPos + size);
98 }
99};
100
102 DeviceInfo const& info,
103 DeviceSpec const& spec,
105 ImVec2 const& size)
106{
107 auto getNumInputs = [&states]() -> size_t {
108 auto& inputsView = states.statesViews[(int)ProcessingStateId::DATA_QUERIES];
109 std::string_view inputs(states.statesBuffer.data() + inputsView.first, inputsView.size);
110 if (inputs.size() == 0) {
111 return 0;
112 }
113 // count the number of semi-colon separators to get number of inputs
114 int numInputs = std::count(inputs.begin(), inputs.end(), ';');
115 return numInputs;
116 };
117 auto getNumRecords = [&states]() -> size_t {
118 auto& view = states.statesViews[(int)ProcessingStateId::DATA_RELAYER_BASE];
119 if (view.size == 0) {
120 return 0;
121 }
122 // The first number is the size of the pipeline
123 int numRecords = strtoul(states.statesBuffer.data() + view.first, nullptr, 10);
124 return numRecords;
125 };
126 auto getRecord = [](size_t i) -> int {
127 return i;
128 };
129 auto getNumItems = [&states](int record) -> int {
130 auto& view = states.statesViews[(int)ProcessingStateId::DATA_RELAYER_BASE + record];
131 if (view.size == 0) {
132 return 0;
133 }
134 char const* beginData = strchr(states.statesBuffer.data() + view.first, ' ') + 1;
135 // The number of elements is given by the size of the state, minus the header
136 int size = view.size - (beginData - (states.statesBuffer.data() + view.first));
137 return size;
138 };
139 auto getItem = [&states](int const& record, size_t i) -> int8_t const* {
140 static int8_t const zero = '0';
141 static int8_t const error = '4';
142 char const *buffer = states.statesBuffer.data();
143 auto& view = states.statesViews[(int)ProcessingStateId::DATA_RELAYER_BASE + record];
144 if (view.size == 0) {
145 return &zero;
146 }
147 char const* const beginData = strchr(buffer + view.first, ' ') + 1;
148 // Protect against buffer overflows
149 if (view.size <= beginData - buffer + i - view.first) {
150 return &error;
151 }
152 return (int8_t const*)beginData + i; };
153 auto getValue = [](int8_t const& item) -> int { return item - '0'; };
154 auto getColor = [](int value) {
155 static const ImU32 SLOT_EMPTY = ImColor(70, 70, 70, 255);
156 static const ImU32 SLOT_FULL = ImColor(PaletteHelpers::RED);
157 static const ImU32 SLOT_DISPATCHED = ImColor(PaletteHelpers::YELLOW);
158 static const ImU32 SLOT_DONE = ImColor(PaletteHelpers::GREEN);
159 static const ImU32 SLOT_ERROR = ImColor(0xfe, 0x43, 0x65, 255);
160 switch (value) {
161 case 0:
162 return SLOT_EMPTY;
163 case 1:
164 return SLOT_FULL;
165 case 2:
166 return SLOT_DISPATCHED;
167 case 3:
168 return SLOT_DONE;
169 }
170 return SLOT_ERROR;
171 };
172 auto describeCell = [&states, &spec](int row, int slot) -> void {
173 ImGui::BeginTooltip();
174
175 // display the input (origin/descr/subspec)
176 auto& inputsView = states.statesViews[(int)ProcessingStateId::DATA_QUERIES];
177 std::string_view inputs(states.statesBuffer.data() + inputsView.first, inputsView.size);
178 auto beginInputs = inputs.begin();
179 auto endInputs = beginInputs + inputsView.size;
180 char const* input = beginInputs;
181 size_t i = 0;
182 while (input != endInputs) {
183 auto end = std::find(input, endInputs, ';');
184 if ((end - input) == 0) {
185 continue;
186 }
187 if (i == row) {
188 ImGui::Text("%d %.*s (%s)", row, int(end - input), input, InspectorHelpers::getLifeTimeStr(spec.inputs[i].matcher.lifetime).c_str());
189 break;
190 }
191 ++i;
192 input = end + 1;
193 }
194
195 // display context variables
196 ImGui::Text("Input query matched values for slot: %d", slot);
197 auto& view = states.statesViews[(short)ProcessingStateId::CONTEXT_VARIABLES_BASE + (short)slot];
198 auto begin = view.first;
199 for (size_t vi = 0; vi < data_matcher::MAX_MATCHING_VARIABLE; ++vi) {
200 std::string_view state(states.statesBuffer.data() + begin, view.size);
201 // find the semi-colon, which separates entries in the variable list
202 auto pos = state.find(';');
203 std::string_view value = state.substr(0, pos);
204 // Do not display empty values.
205 if (value.empty()) {
206 begin += 1;
207 continue;
208 }
209 switch (vi) {
211 ImGui::Text("$%zu (startTime): %.*s", vi, (int)value.size(), value.data());
212 break;
214 ImGui::Text("$%zu (tfCounter): %.*s", vi, (int)value.size(), value.data());
215 break;
217 ImGui::Text("$%zu (firstTForbit): %.*s", vi, (int)value.size(), value.data());
218 break;
219 default:
220 ImGui::Text("$%zu: %.*s", vi, (int)value.size(), value.data());
221 }
222 begin += pos + 1;
223 }
224 ImGui::EndTooltip();
225 };
226
227 if (getNumRecords()) {
228 HeatMapHelper::draw<int, int8_t>("DataRelayer",
229 size,
230 getNumInputs,
231 getNumRecords,
232 getRecord,
233 getNumItems,
234 getItem,
235 getValue,
236 getColor,
237 describeCell);
238 }
239}
240
241} // namespace o2::framework::gui
benchmark::State & state
uint16_t padding
int32_t i
uint16_t pos
Definition RawData.h:3
GLuint buffer
Definition glcorearb.h:655
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
GLuint const GLchar * name
Definition glcorearb.h:781
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
Definition glcorearb.h:5500
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 &metrics, DeviceInfo const &info, DeviceSpec const &spec, DataProcessingStates const &states, ImVec2 const &size)
View of the DataRelayer metrics for a given DeviceInfo.
D const SVectorGPU< T, D > & rhs
Definition SMatrixGPU.h:191
Vertex< T > operator-(const Vertex< T > &a, const Vertex< T > &b)
Definition Vertex.h:98
BinCenterView< AxisIterator > operator+(BinCenterView< AxisIterator > lhs, int n)
std::vector< InputRoute > inputs
Definition DeviceSpec.h:62
static const std::string getLifeTimeStr(Lifetime lifetime)
static void draw(const char *name, 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)
std::vector< int > row