Skip to content

Commit 2df6d04

Browse files
committed
DPL GUI: display metrics for input and output channels
This adds labels to each of the channels in input and in output. In particular the current implementation allows to display the oldest possible timeslice as seen by the inputs and the one notified on the output. Notice that due to the way sending works, the metric on the output channel might be somewhat delayed wrt its real value.
1 parent 80a6d5d commit 2df6d04

File tree

8 files changed

+293
-16
lines changed

8 files changed

+293
-16
lines changed

Framework/Core/include/Framework/CommonServices.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ struct CommonServices {
8181
static ServiceSpec ccdbSupportSpec();
8282
static ServiceSpec decongestionSpec();
8383
static ServiceSpec asyncQueue();
84+
static ServiceSpec guiMetricsSpec();
8485

8586
static std::vector<ServiceSpec> defaultServices(int numWorkers = 0);
8687
static std::vector<ServiceSpec> requiredServices();

Framework/Core/include/Framework/DeviceInfo.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ struct DeviceInfo {
7272
Metric2DViewIndex queriesViewIndex;
7373
/// Index for the queries of each input route.
7474
Metric2DViewIndex outputsViewIndex;
75+
/// Index for the metrics to be displayed associated to
76+
/// each input channel of the device.
77+
Metric2DViewIndex inputChannelMetricsViewIndex;
78+
/// Index for the metrics to be displayed associated to
79+
/// each input channel of the device.
80+
Metric2DViewIndex outputChannelMetricsViewIndex;
81+
7582
/// Current configuration for the device
7683
boost::property_tree::ptree currentConfig;
7784
/// Current provenance for the configuration keys

Framework/Core/include/Framework/DeviceMetricsInfo.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define O2_FRAMEWORK_DEVICEMETRICSINFO_H_
1414

1515
#include "Framework/RuntimeError.h"
16+
#include "Framework/Traits.h"
1617
#include <array>
1718
#include <cstddef>
1819
#include <string>
@@ -106,6 +107,24 @@ struct DeviceMetricsInfo {
106107
std::vector<bool> changed;
107108
};
108109

110+
struct DeviceMetricsInfoHelpers {
111+
template <typename T>
112+
static std::array<T, 1024> const& get(DeviceMetricsInfo const& info, size_t metricIdx)
113+
{
114+
if constexpr (std::is_same_v<T, int>) {
115+
return info.intMetrics[metricIdx];
116+
} else if constexpr (std::is_same_v<T, uint64_t>) {
117+
return info.uint64Metrics[metricIdx];
118+
} else if constexpr (std::is_same_v<T, StringMetric>) {
119+
return info.stringMetrics[metricIdx];
120+
} else if constexpr (std::is_same_v<T, float>) {
121+
return info.floatMetrics[metricIdx];
122+
} else {
123+
static_assert(always_static_assert_v<T>, "Unsupported type");
124+
}
125+
}
126+
};
127+
109128
} // namespace o2::framework
110129

111130
#endif // O2_FRAMEWORK_DEVICEMETRICSINFO_H_

Framework/Core/include/Framework/Metric2DViewIndex.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,15 @@
88
// In applying this license CERN does not waive the privileges and immunities
99
// granted to it by virtue of its status as an Intergovernmental Organization
1010
// or submit itself to any jurisdiction.
11-
#ifndef o2_framework_Metric2DViewInfo_H_INCLUDED
12-
#define o2_framework_Metric2DViewInfo_H_INCLUDED
11+
#ifndef O2_FRAMEWORK_METRIC2DVIEWINDEX_H_
12+
#define O2_FRAMEWORK_METRIC2DVIEWINDEX_H_
1313

1414
#include <functional>
1515
#include <cstddef>
1616
#include <string>
1717
#include <vector>
1818

19-
namespace o2
20-
{
21-
namespace framework
19+
namespace o2::framework
2220
{
2321

2422
struct MetricInfo;
@@ -42,7 +40,6 @@ struct Metric2DViewIndex {
4240
static Updater getUpdater(std::vector<Metric2DViewIndex*> views);
4341
};
4442

45-
} // namespace framework
46-
} // namespace o2
43+
} // namespace o2::framework
4744

48-
#endif // o2_framework_Metric2DViewInfo_H_INCLUDED
45+
#endif // O2_FRAMEWORK_METRIC2DVIEWINDEX_H_

Framework/Core/src/CommonServices.cxx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,39 @@ o2::framework::ServiceSpec CommonServices::dataProcessingStats()
864864
.kind = ServiceKind::Serial};
865865
}
866866

867+
struct GUIMetrics {
868+
};
869+
870+
o2::framework::ServiceSpec CommonServices::guiMetricsSpec()
871+
{
872+
return ServiceSpec{
873+
.name = "gui-metrics",
874+
.init = [](ServiceRegistry& services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle {
875+
GUIMetrics* stats = new GUIMetrics();
876+
auto& monitoring = services.get<Monitoring>();
877+
auto& spec = services.get<DeviceSpec const>();
878+
monitoring.send({(int)spec.inputChannels.size(), fmt::format("oldest_possible_timeslice/h"), o2::monitoring::Verbosity::Debug});
879+
monitoring.send({(int)1, fmt::format("oldest_possible_timeslice/w"), o2::monitoring::Verbosity::Debug});
880+
monitoring.send({(int)spec.outputChannels.size(), fmt::format("oldest_possible_output/h"), o2::monitoring::Verbosity::Debug});
881+
monitoring.send({(int)1, fmt::format("oldest_possible_output/w"), o2::monitoring::Verbosity::Debug});
882+
return ServiceHandle{TypeIdHelpers::uniqueId<GUIMetrics>(), stats};
883+
},
884+
.configure = noConfiguration(),
885+
.postProcessing = [](ProcessingContext& context, void* service) {
886+
auto& relayer = context.services().get<DataRelayer>();
887+
auto& monitoring = context.services().get<Monitoring>();
888+
auto& spec = context.services().get<DeviceSpec const>();
889+
auto oldestPossibleOutput = relayer.getOldestPossibleOutput();
890+
for (size_t ci; ci < spec.outputChannels.size(); ++ci) {
891+
monitoring.send({(uint64_t)oldestPossibleOutput.timeslice.value, fmt::format("oldest_possible_output/{}", ci), o2::monitoring::Verbosity::Debug});
892+
} },
893+
.domainInfoUpdated = [](ServiceRegistry& registry, size_t timeslice, ChannelIndex channel) {
894+
auto& monitoring = registry.get<Monitoring>();
895+
monitoring.send({(uint64_t)timeslice, fmt::format("oldest_possible_timeslice/{}", channel.value), o2::monitoring::Verbosity::Debug}); },
896+
.active = false,
897+
.kind = ServiceKind::Serial};
898+
}
899+
867900
o2::framework::ServiceSpec CommonServices::objectCache()
868901
{
869902
return ServiceSpec{
@@ -903,6 +936,9 @@ std::vector<ServiceSpec> CommonServices::defaultServices(int numThreads)
903936
CommonMessageBackends::stringBackendSpec(),
904937
decongestionSpec(),
905938
CommonMessageBackends::rawBufferBackendSpec()};
939+
940+
// I should make it optional depending wether the GUI is there or not...
941+
specs.push_back(CommonServices::guiMetricsSpec());
906942
if (numThreads) {
907943
specs.push_back(threadPool(numThreads));
908944
}

Framework/Core/src/ControlWebSocketHandler.cxx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ void ControlWebSocketHandler::frame(char const* frame, size_t s)
2424
auto updateMetricsViews = Metric2DViewIndex::getUpdater({&(*mContext.infos)[mIndex].dataRelayerViewIndex,
2525
&(*mContext.infos)[mIndex].variablesViewIndex,
2626
&(*mContext.infos)[mIndex].queriesViewIndex,
27-
&(*mContext.infos)[mIndex].outputsViewIndex});
27+
&(*mContext.infos)[mIndex].outputsViewIndex,
28+
&(*mContext.infos)[mIndex].inputChannelMetricsViewIndex,
29+
&(*mContext.infos)[mIndex].outputChannelMetricsViewIndex});
2830

2931
auto newMetricCallback = [&updateMetricsViews, &metrics = mContext.metrics, &hasNewMetric](std::string const& name, MetricInfo const& metric, int value, size_t metricIndex) {
3032
updateMetricsViews(name, metric, value, metricIndex);

Framework/Core/src/runDataProcessing.cxx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@ void spawnRemoteDevice(std::string const&,
346346
info.variablesViewIndex = Metric2DViewIndex{"matcher_variables", 0, 0, {}};
347347
info.queriesViewIndex = Metric2DViewIndex{"data_queries", 0, 0, {}};
348348
info.outputsViewIndex = Metric2DViewIndex{"output_matchers", 0, 0, {}};
349+
info.inputChannelMetricsViewIndex = Metric2DViewIndex{"oldest_possible_timeslice", 0, 0, {}};
350+
info.outputChannelMetricsViewIndex = Metric2DViewIndex{"oldest_possible_output", 0, 0, {}};
349351
// FIXME: use uv_now.
350352
info.lastSignal = uv_hrtime() - 10000000;
351353

@@ -464,7 +466,8 @@ struct ControlWebSocketHandler : public WebSocketHandler {
464466
auto updateMetricsViews = Metric2DViewIndex::getUpdater({&(*mContext.infos)[mIndex].dataRelayerViewIndex,
465467
&(*mContext.infos)[mIndex].variablesViewIndex,
466468
&(*mContext.infos)[mIndex].queriesViewIndex,
467-
&(*mContext.infos)[mIndex].outputsViewIndex});
469+
&(*mContext.infos)[mIndex].outputsViewIndex,
470+
&(*mContext.infos)[mIndex].inputChannelMetricsViewIndex});
468471

469472
auto newMetricCallback = [&updateMetricsViews, &hasNewMetric](std::string const& name, MetricInfo const& metric, int value, size_t metricIndex) {
470473
updateMetricsViews(name, metric, value, metricIndex);
@@ -826,6 +829,8 @@ void spawnDevice(DeviceRef ref,
826829
info.variablesViewIndex = Metric2DViewIndex{"matcher_variables", 0, 0, {}};
827830
info.queriesViewIndex = Metric2DViewIndex{"data_queries", 0, 0, {}};
828831
info.outputsViewIndex = Metric2DViewIndex{"output_matchers", 0, 0, {}};
832+
info.inputChannelMetricsViewIndex = Metric2DViewIndex{"oldest_possible_timeslice", 0, 0, {}};
833+
info.outputChannelMetricsViewIndex = Metric2DViewIndex{"oldest_possible_output", 0, 0, {}};
829834
info.tracyPort = driverInfo.tracyPort;
830835
info.lastSignal = uv_hrtime() - 10000000;
831836

0 commit comments

Comments
 (0)