Skip to content

Commit f94e832

Browse files
committed
DPL GUI: Improve GUI to debug relaying process
This allows full debugging of the new DataRelayer, including the status of the variables and the queries on the data. It also provides a table view to check (the first 10 numbers of) each metric.
1 parent 171c26f commit f94e832

14 files changed

Lines changed: 229 additions & 89 deletions

Framework/Core/include/Framework/DataRelayer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,10 @@ class DataRelayer {
100100
std::vector<size_t> mDistinctRoutesIndex;
101101
std::vector<data_matcher::DataDescriptorMatcher> mInputMatchers;
102102
std::vector<data_matcher::VariableContext> mVariableContextes;
103+
103104
static std::vector<std::string> sMetricsNames;
105+
static std::vector<std::string> sVariablesMetricsNames;
106+
static std::vector<std::string> sQueriesMetricsNames;
104107
};
105108

106109
} // namespace framework

Framework/Core/include/Framework/DeviceInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ struct DeviceInfo {
5050
bool readyToQuit;
5151
/// Index for a particular relayer.
5252
Metric2DViewIndex dataRelayerViewIndex;
53+
/// Index for the variables of a given relayer.
54+
Metric2DViewIndex variablesViewIndex;
55+
/// Index for the queries of each input route.
56+
Metric2DViewIndex queriesViewIndex;
5357
};
5458

5559
} // namespace framework

Framework/Core/include/Framework/DeviceMetricsInfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ struct DeviceMetricsInfo {
6464
struct DeviceMetricsHelper {
6565
/// Type of the callback which can be provided to be invoked every time a new
6666
/// metric is found by the system.
67-
using NewMetricCallback = std::function<void(std::string const&, MetricInfo const&, int value)>;
67+
using NewMetricCallback = std::function<void(std::string const&, MetricInfo const&, int value, size_t metricIndex)>;
6868

6969
/// Helper function to parse a metric string.
7070
static bool parseMetric(const std::string& s, std::smatch& match);

Framework/Core/include/Framework/Metric2DViewIndex.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct MetricInfo;
2525
/// This allows keeping track of the metrics which should be grouped together
2626
/// in some sort of 2D representation.
2727
struct Metric2DViewIndex {
28-
using Updater = std::function<void(std::string const&, MetricInfo const&, int)>;
28+
using Updater = std::function<void(std::string const&, MetricInfo const&, int value, size_t metricIndex)>;
2929
/// The prefix in the metrics store to be used for the view
3030
std::string prefix;
3131
/// The size in X of the metrics
@@ -37,7 +37,8 @@ struct Metric2DViewIndex {
3737
/// Whether or not the view is ready to be used.
3838
bool isComplete() const { return (w * h) != 0; }
3939

40-
static Updater getUpdater(Metric2DViewIndex& view);
40+
/// Get the right updated function given a list of Metric views
41+
static Updater getUpdater(std::vector<Metric2DViewIndex*> views);
4142
};
4243

4344
} // namespace framework

Framework/Core/src/DataRelayer.cxx

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ DataRelayer::DataRelayer(const CompletionPolicy& policy,
9797
for (size_t ci = 0; ci < mCache.size(); ci++) {
9898
metrics.send({ 0, sMetricsNames[ci] });
9999
}
100+
for (size_t ci = 0; ci < mVariableContextes.size() * 16; ci++) {
101+
metrics.send({ std::string("null"), sVariablesMetricsNames[ci] });
102+
}
100103
}
101104

102105
void DataRelayer::processDanglingInputs(std::vector<ExpirationHandler> const& expirationHandlers,
@@ -149,6 +152,25 @@ size_t matchToContext(void* data,
149152
return INVALID_INPUT;
150153
}
151154

155+
/// Send the contents of a context as metrics, so that we can examine them in
156+
/// the GUI.
157+
void sendVariableContextMetrics(VariableContext& context, TimesliceSlot slot,
158+
monitoring::Monitoring& metrics, std::vector<std::string> const& names)
159+
{
160+
const std::string nullstring{"null"};
161+
162+
for (size_t i = 0; i < MAX_MATCHING_VARIABLE; i++) {
163+
auto& var = context.get(i);
164+
if (auto pval = std::get_if<uint64_t>(&var)) {
165+
metrics.send(monitoring::Metric{ std::to_string(*pval), names[16 * slot.index + i] });
166+
} else if (auto pval2 = std::get_if<std::string>(&var)) {
167+
metrics.send(monitoring::Metric{ *pval2, names[16 * slot.index + i] });
168+
} else {
169+
metrics.send(monitoring::Metric{ nullstring, names[16 * slot.index + i] });
170+
}
171+
}
172+
}
173+
152174
DataRelayer::RelayChoice
153175
DataRelayer::relay(std::unique_ptr<FairMQMessage> &&header,
154176
std::unique_ptr<FairMQMessage> &&payload) {
@@ -273,6 +295,7 @@ DataRelayer::relay(std::unique_ptr<FairMQMessage> &&header,
273295
if (input != INVALID_INPUT && TimesliceId::isValid(timeslice) && TimesliceSlot::isValid(slot)) {
274296
LOG(DEBUG) << "Received timeslice " << timeslice.value;
275297
saveInSlot(timeslice, input, slot);
298+
sendVariableContextMetrics(index.getVariablesForSlot(slot), slot, mMetrics, sVariablesMetricsNames);
276299
index.markAsDirty(slot, true);
277300
return WillRelay;
278301
}
@@ -303,6 +326,7 @@ DataRelayer::relay(std::unique_ptr<FairMQMessage> &&header,
303326
// cache still holds the old data, so we prune it.
304327
pruneCache(slot);
305328
saveInSlot(timeslice, input, slot);
329+
sendVariableContextMetrics(pristineContext, slot, mMetrics, sVariablesMetricsNames);
306330
index.markAsDirty(slot, true);
307331

308332
return WillRelay;
@@ -449,10 +473,36 @@ DataRelayer::setPipelineLength(size_t s) {
449473
sMetricsNames.resize(mCache.size());
450474
for (size_t i = 0; i < sMetricsNames.size(); ++i) {
451475
sMetricsNames[i] = std::string("data_relayer/") + std::to_string(i);
476+
//mMetrics.send({ 0, sMetricsNames[i] });
477+
}
478+
// There is maximum 16 variables available. We keep them row-wise so that
479+
// that we can take mod 16 of the index to understand which variable we
480+
// are talking about.
481+
sVariablesMetricsNames.resize(mVariableContextes.size() * 16);
482+
mMetrics.send({ (int)16, "matcher_variables/w" });
483+
mMetrics.send({ (int)mVariableContextes.size(), "matcher_variables/h" });
484+
for (size_t i = 0; i < sVariablesMetricsNames.size(); ++i) {
485+
sVariablesMetricsNames[i] = std::string("matcher_variables/") + std::to_string(i);
486+
mMetrics.send({ std::string("null"), sVariablesMetricsNames[i % 16] });
487+
}
488+
// The queries are all the same, so we only have width 1
489+
sQueriesMetricsNames.resize(numInputTypes * 1);
490+
mMetrics.send({ (int)numInputTypes, "data_queries/h" });
491+
mMetrics.send({ (int)1, "data_queries/w" });
492+
for (size_t i = 0; i < numInputTypes; ++i) {
493+
sQueriesMetricsNames[i] = std::string("data_queries/") + std::to_string(i);
494+
char buffer[128];
495+
auto& matcher = mInputRoutes[mDistinctRoutesIndex[i]].matcher;
496+
snprintf(buffer, 127, "%s/%s/%llu",
497+
matcher.origin.str,
498+
matcher.description.str,
499+
matcher.subSpec);
500+
mMetrics.send({ std::string(buffer), sQueriesMetricsNames[i] });
452501
}
453502
}
454503

455504
std::vector<std::string> DataRelayer::sMetricsNames;
456-
505+
std::vector<std::string> DataRelayer::sVariablesMetricsNames;
506+
std::vector<std::string> DataRelayer::sQueriesMetricsNames;
457507
}
458508
}

Framework/Core/src/DeviceMetricsInfo.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ bool DeviceMetricsHelper::processMetric(const std::smatch& match,
125125
assert(metricInfo.storeIdx != -1);
126126
assert(metricLabelIdx.first.empty() == false);
127127
if (newMetricsCallback != nullptr) {
128-
newMetricsCallback(metricLabelIdx.first, metricInfo, intValue);
128+
newMetricsCallback(metricLabelIdx.first, metricInfo, intValue, metricIndex);
129129
}
130130
info.metrics.push_back(metricInfo);
131131
} else {

Framework/Core/src/FrameworkGUIDataRelayerUsage.cxx

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "Framework/DeviceMetricsInfo.h"
1313
#include "Framework/DeviceInfo.h"
1414
#include <iostream>
15+
#include <cmath>
1516

1617
static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
1718
static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }
@@ -27,13 +28,14 @@ namespace gui
2728
struct HeatMapHelper {
2829
template <typename RECORD, typename ITEM>
2930
static void draw(const char* name,
30-
ImVec2 const &sizeHint,
31+
ImVec2 const& sizeHint,
3132
std::function<size_t()> const& getNumRecords,
3233
std::function<RECORD(size_t)> const& getRecord,
3334
std::function<size_t(RECORD const&)> const& getNumItems,
3435
std::function<ITEM const&(RECORD const&, size_t)> const& getItem,
3536
std::function<int(ITEM const&)> const& getValue,
36-
std::function<ImU32(int value)> const& getColor)
37+
std::function<ImU32(int value)> const& getColor,
38+
std::function<void(int row, int column)> const& describeCell)
3739
{
3840
ImVec2 size = ImVec2(sizeHint.x, std::min(sizeHint.y, 16.f * getNumItems(0) + 2));
3941
ImU32 BORDER_COLOR = ImColor(200, 200, 200, 255);
@@ -42,6 +44,17 @@ struct HeatMapHelper {
4244
constexpr float MAX_BOX_Y_SIZE = 16.f;
4345
ImDrawList* drawList = ImGui::GetWindowDrawList();
4446
ImVec2 winPos = ImGui::GetCursorScreenPos();
47+
auto records = getNumRecords();
48+
auto boxSizeX = std::min(size.x / records, MAX_BOX_X_SIZE);
49+
50+
ImGui::InvisibleButton("sensible area", ImVec2(size.x, size.y));
51+
if (ImGui::IsItemHovered()) {
52+
auto pos = ImGui::GetMousePos() - winPos;
53+
auto slot = std::lround(std::trunc(pos.x / size.x * records));
54+
auto row = std::lround(std::trunc(pos.y / size.y));
55+
describeCell(row, slot);
56+
}
57+
4558
drawList->AddQuadFilled(
4659
ImVec2(0., 0.) + winPos,
4760
ImVec2{ size.x, 0 } + winPos,
@@ -55,7 +68,6 @@ struct HeatMapHelper {
5568
ImVec2{ 0, size.y} + winPos,
5669
BORDER_COLOR);
5770
float padding = 1;
58-
auto boxSizeX = std::min(size.x / getNumRecords(), MAX_BOX_X_SIZE);
5971
for (size_t ri = 0, re = getNumRecords(); ri < re; ri++) {
6072
auto record = getRecord(ri);
6173
ImVec2 xOffset{ (ri * boxSizeX) + padding, 0 };
@@ -64,6 +76,7 @@ struct HeatMapHelper {
6476
for (size_t mi = 0, me = getNumItems(record); mi < me; mi++) {
6577
ImVec2 yOffSet{ 0, (mi * boxSizeY) + padding };
6678
ImVec2 ySize{ 0, boxSizeY - 2 * padding };
79+
6780
drawList->AddQuadFilled(
6881
xOffset + yOffSet + winPos,
6982
xOffset + xSize + yOffSet + winPos,
@@ -82,6 +95,8 @@ void displayDataRelayer(DeviceMetricsInfo const& metrics,
8295
ImVec2 const &size)
8396
{
8497
auto& viewIndex = info.dataRelayerViewIndex;
98+
auto& variablesIndex = info.variablesViewIndex;
99+
auto& queriesIndex = info.queriesViewIndex;
85100

86101
auto getNumRecords = [&viewIndex]() -> size_t {
87102
if (viewIndex.isComplete()) {
@@ -126,6 +141,19 @@ void displayDataRelayer(DeviceMetricsInfo const& metrics,
126141
}
127142
return SLOT_ERROR;
128143
};
144+
auto describeCell = [&metrics, &variablesIndex, &queriesIndex](int input, int slot) -> void {
145+
ImGui::BeginTooltip();
146+
for (size_t vi = 0; vi < variablesIndex.w; ++vi) {
147+
auto idx = (slot * variablesIndex.w) + vi;
148+
assert(idx < variablesIndex.indexes.size());
149+
MetricInfo const& metricInfo = metrics.metrics[variablesIndex.indexes[idx]];
150+
assert(metricInfo.storeIdx < metrics.stringMetrics.size());
151+
//assert(metricInfo.type == MetricType::String);
152+
auto& data = metrics.stringMetrics[metricInfo.storeIdx];
153+
ImGui::Text("$%zu: %s", vi, data[(metricInfo.pos - 1) % data.size()].data);
154+
}
155+
ImGui::EndTooltip();
156+
};
129157

130158
if (getNumRecords()) {
131159
HeatMapHelper::draw<int, int>("DataRelayer",
@@ -135,7 +163,8 @@ void displayDataRelayer(DeviceMetricsInfo const& metrics,
135163
getNumItems,
136164
getItem,
137165
getValue,
138-
getColor);
166+
getColor,
167+
describeCell);
139168
}
140169
}
141170

Framework/Core/src/FrameworkGUIDebugger.cxx

Lines changed: 68 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
#include "Framework/PaletteHelpers.h"
2525
#include "Framework/FrameworkGUIState.h"
2626

27+
// Simplify debugging
28+
template class std::vector<o2::framework::DeviceMetricsInfo>;
29+
2730
static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
2831
static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }
2932

@@ -296,40 +299,44 @@ void displayDeviceMetrics(const char* label, ImVec2 canvasSize, std::string cons
296299
}
297300
}
298301

299-
void metricsTable(gui::WorkspaceGUIState& globalGUIState, const DeviceMetricsInfo& metricsInfo)
300-
{
301-
/// Nothing to draw, if no metric selected.
302-
if (globalGUIState.selectedMetric == -1) {
303-
return;
304-
}
302+
struct ColumnInfo {
303+
MetricType type;
304+
int index;
305+
};
305306

306-
auto currentMetricName = globalGUIState.availableMetrics[globalGUIState.selectedMetric];
307+
void metricsTableRow(std::vector<ColumnInfo> columnInfos,
308+
std::vector<DeviceMetricsInfo> const& metricsInfos,
309+
int row)
310+
{
311+
ImGui::Text("%d", row);
312+
ImGui::NextColumn();
307313

308-
size_t i = DeviceMetricsHelper::metricIdxByName(currentMetricName, metricsInfo);
314+
for (size_t j = 0; j < columnInfos.size(); j++) {
315+
auto& info = columnInfos[j];
316+
auto& metricsInfo = metricsInfos[j];
309317

310-
// We did not find any plot, skipping this.
311-
if (i == metricsInfo.metricLabelsIdx.size()) {
312-
ImGui::TextUnformatted("-");
313-
ImGui::NextColumn();
314-
return;
315-
}
316-
auto& metric = metricsInfo.metrics[i];
317-
switch (metric.type) {
318-
case MetricType::Int: {
319-
ImGui::Text("%i", metricsInfo.intMetrics[metric.storeIdx][0]);
320-
ImGui::NextColumn();
321-
} break;
322-
case MetricType::Float: {
323-
ImGui::Text("%f", metricsInfo.floatMetrics[metric.storeIdx][0]);
324-
ImGui::NextColumn();
325-
} break;
326-
case MetricType::String: {
327-
ImGui::Text("%s", metricsInfo.stringMetrics[metric.storeIdx][0].data);
328-
ImGui::NextColumn();
329-
} break;
330-
default:
318+
if (info.index == -1) {
319+
ImGui::TextUnformatted("-");
331320
ImGui::NextColumn();
332-
break;
321+
continue;
322+
}
323+
switch (info.type) {
324+
case MetricType::Int: {
325+
ImGui::Text("%i (%i)", metricsInfo.intMetrics[info.index][row], info.index);
326+
ImGui::NextColumn();
327+
} break;
328+
case MetricType::Float: {
329+
ImGui::Text("%f (%i)", metricsInfo.floatMetrics[info.index][row], info.index);
330+
ImGui::NextColumn();
331+
} break;
332+
case MetricType::String: {
333+
ImGui::Text("%s (%i)", metricsInfo.stringMetrics[info.index][row].data, info.index);
334+
ImGui::NextColumn();
335+
} break;
336+
default:
337+
ImGui::NextColumn();
338+
break;
339+
}
333340
}
334341
}
335342

@@ -397,6 +404,31 @@ void historyBar(gui::WorkspaceGUIState& globalGUIState, size_t rangeBegin, size_
397404
}
398405
}
399406

407+
/// Calculate where to find the coliumns for a give metric
408+
std::vector<ColumnInfo> calculateTableIndex(gui::WorkspaceGUIState& globalGUIState, int selectedMetric, std::vector<DeviceMetricsInfo> const& metricsInfos)
409+
{
410+
std::vector<ColumnInfo> columns;
411+
for (size_t j = 0; j < globalGUIState.devices.size(); ++j) {
412+
const DeviceMetricsInfo& metricsInfo = metricsInfos[j];
413+
/// Nothing to draw, if no metric selected.
414+
if (selectedMetric == -1) {
415+
columns.push_back({ MetricType::Int, -1 });
416+
continue;
417+
}
418+
auto currentMetricName = globalGUIState.availableMetrics[selectedMetric];
419+
size_t idx = DeviceMetricsHelper::metricIdxByName(currentMetricName, metricsInfo);
420+
421+
// We did not find any plot, skipping this.
422+
if (idx == metricsInfo.metricLabelsIdx.size()) {
423+
columns.push_back({ MetricType::Int, -1 });
424+
continue;
425+
}
426+
auto metric = metricsInfos[j].metrics[idx];
427+
columns.push_back({ metric.type, static_cast<int>(metric.storeIdx) });
428+
}
429+
return columns;
430+
};
431+
400432
void displayDeviceHistograms(gui::WorkspaceGUIState& state,
401433
const std::vector<DeviceInfo>& infos, const std::vector<DeviceSpec>& devices,
402434
std::vector<DeviceControl>& controls, const std::vector<DeviceMetricsInfo>& metricsInfos)
@@ -519,7 +551,6 @@ void displayDeviceHistograms(gui::WorkspaceGUIState& state,
519551
for (size_t j = 0; j < state.devices.size(); ++j) {
520552
gui::DeviceGUIState& deviceGUIState = state.devices[j];
521553
const DeviceSpec& spec = devices[j];
522-
const DeviceMetricsInfo& metricsInfo = metricsInfos[j];
523554

524555
ImGui::SetColumnOffset(-1, offset);
525556
textsize = ImGui::CalcTextSize(spec.name.c_str(), NULL, true);
@@ -528,16 +559,13 @@ void displayDeviceHistograms(gui::WorkspaceGUIState& state,
528559
ImGui::NextColumn();
529560
}
530561
ImGui::Separator();
562+
563+
auto columns = calculateTableIndex(state, state.selectedMetric, metricsInfos);
564+
565+
// Calculate which columns we want to see.
531566
// FIXME: only one column for now.
532-
for (size_t i = 0; i < 1; ++i) {
533-
ImGui::Text("%li", i);
534-
ImGui::NextColumn();
535-
for (size_t j = 0; j < state.devices.size(); ++j) {
536-
gui::DeviceGUIState& deviceGUIState = state.devices[j];
537-
const DeviceSpec& spec = devices[j];
538-
const DeviceMetricsInfo& metricsInfo = metricsInfos[j];
539-
metricsTable(state, metricsInfo);
540-
}
567+
for (size_t i = 0; i < 10; ++i) {
568+
metricsTableRow(columns, metricsInfos, i);
541569
}
542570
ImGui::Columns(1);
543571

0 commit comments

Comments
 (0)