Skip to content

Commit 35131aa

Browse files
committed
DPL: support strings and other metrics improvements
Each string metric has a limited history of 32 entries and values can have up to 128 (including \0 termination). This also introduces a new table view to display the last entries in the string metrics and makes sure we do not die when visualizing strings. We also add a benchmark for the metrics. Current results: Run on (8 X 2500 MHz CPU s) 2018-11-09 21:11:01 -------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------- BM_ParseIntMetric 22010 ns 21998 ns 31739 BM_ProcessIntMetric 22765 ns 22759 ns 28960 BM_ParseFloatMetric 23098 ns 23093 ns 30186 BM_ProcessFloatMetric 24515 ns 24511 ns 27653 BM_ProcessStringMetric 30352 ns 30348 ns 22827
1 parent 6ee9474 commit 35131aa

File tree

6 files changed

+326
-81
lines changed

6 files changed

+326
-81
lines changed

Framework/Core/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,9 @@ set(TEST_SRCS
257257
set(BENCH_SRCS
258258
test/benchmark_DataDescriptorMatcher.cxx
259259
test/benchmark_DataRelayer.cxx
260-
test/benchmark_InputRecord.cxx)
260+
test/benchmark_DeviceMetricsInfo.cxx
261+
test/benchmark_InputRecord.cxx
262+
)
261263

262264
O2_GENERATE_TESTS(
263265
MODULE_LIBRARY_NAME ${LIBRARY_NAME}

Framework/Core/include/Framework/DeviceMetricsInfo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace framework
2525

2626
enum class MetricType {
2727
Int,
28+
String,
2829
Float,
2930
Unknown
3031
};
@@ -37,10 +38,19 @@ struct MetricInfo {
3738
size_t pos; // Last position in the circular buffer
3839
};
3940

41+
// We keep only fixed lenght strings for metrics, as in the end this is not
42+
// really needed. They should be nevertheless 0 terminated.
43+
struct StringMetric {
44+
char data[128];
45+
};
46+
4047
/// This struct hold information about device metrics when running
4148
/// in standalone mode
4249
struct DeviceMetricsInfo {
50+
// We keep the size of each metric to 4096 bytes. No need for more
51+
// for the debug GUI
4352
std::vector<std::array<int, 1024>> intMetrics;
53+
std::vector<std::array<StringMetric, 32>> stringMetrics; // We do not keep so many strings as metrics as history is less relevant.
4454
std::vector<std::array<float, 1024>> floatMetrics;
4555
std::vector<std::array<size_t, 1024>> timestamps;
4656
std::vector<float> max;

Framework/Core/src/DeviceMetricsInfo.cxx

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace framework
2828
// [METRIC] <name>,<type> <value> <timestamp> [<tags>]
2929
bool DeviceMetricsHelper::parseMetric(const std::string& s, std::smatch& match)
3030
{
31-
const static std::regex metricsRE(R"regex(\[METRIC\] ([a-zA-Z0-9/_-]+),(0|1|2|4) ([0-9.]+) ([0-9]+))regex", std::regex::optimize);
31+
static std::regex metricsRE(R"regex(\[METRIC\] ([a-zA-Z0-9/_-]+),(0|1|2|4) ([0-9.a-zA-Z_/]+) ([0-9]+))regex", std::regex::optimize);
3232
return std::regex_search(s, match, metricsRE);
3333
}
3434

@@ -43,27 +43,26 @@ bool DeviceMetricsHelper::processMetric(const std::smatch& match,
4343
if (ep == nullptr || *ep != '\0') {
4444
return false;
4545
}
46-
auto stringValue = match[3];
46+
auto valueMatch = match[3];
4747
size_t metricIndex = -1;
4848

49-
auto metricType = MetricType::Unknown;
50-
if (type.str() == "0") {
51-
metricType = MetricType::Int;
52-
} else if (type.str() == "2") {
53-
metricType = MetricType::Float;
54-
}
49+
auto metricType = static_cast<MetricType>(std::stoi(type.str(), 0, 10));
5550

5651
int intValue = 0;
52+
StringMetric stringValue;
5753
float floatValue = 0;
5854
switch (metricType) {
5955
case MetricType::Int:
60-
intValue = strtol(stringValue.str().c_str(), &ep, 10);
56+
intValue = strtol(valueMatch.str().c_str(), &ep, 10);
6157
if (!ep || *ep != '\0') {
6258
return false;
6359
}
6460
break;
61+
case MetricType::String:
62+
strncpy(stringValue.data, valueMatch.str().c_str(), sizeof(stringValue.data) - 1);
63+
break;
6564
case MetricType::Float:
66-
floatValue = strtof(stringValue.str().c_str(), &ep);
65+
floatValue = strtof(valueMatch.str().c_str(), &ep);
6766
if (!ep || *ep != '\0') {
6867
return false;
6968
}
@@ -97,6 +96,10 @@ bool DeviceMetricsHelper::processMetric(const std::smatch& match,
9796
metricInfo.storeIdx = info.intMetrics.size();
9897
info.intMetrics.emplace_back(std::array<int, 1024>{});
9998
break;
99+
case MetricType::String:
100+
metricInfo.storeIdx = info.stringMetrics.size();
101+
info.stringMetrics.emplace_back(std::array<StringMetric, 32>{});
102+
break;
100103
case MetricType::Float:
101104
metricInfo.storeIdx = info.floatMetrics.size();
102105
info.floatMetrics.emplace_back(std::array<float, 1024>{});
@@ -132,39 +135,50 @@ bool DeviceMetricsHelper::processMetric(const std::smatch& match,
132135
// We are now guaranteed our metric is present at metricIndex.
133136
MetricInfo &metricInfo = info.metrics[metricIndex];
134137

135-
auto mod = info.timestamps[metricIndex].size();
138+
// auto mod = info.timestamps[metricIndex].size();
136139
info.minDomain[metricIndex] = std::min(info.minDomain[metricIndex], (size_t)timestamp);
137140
info.maxDomain[metricIndex] = std::max(info.maxDomain[metricIndex], (size_t)timestamp);
138141

139142
switch(metricInfo.type) {
140143
case MetricType::Int: {
141-
intValue = strtol(stringValue.str().c_str(), &ep, 10);
144+
intValue = strtol(valueMatch.str().c_str(), &ep, 10);
142145
if (!ep || *ep != '\0') {
143146
return false;
144147
}
145148
info.intMetrics[metricInfo.storeIdx][metricInfo.pos] = intValue;
146149
info.max[metricIndex] = std::max(info.max[metricIndex], (float)intValue);
147150
info.min[metricIndex] = std::min(info.min[metricIndex], (float)intValue);
151+
// Save the timestamp for the current metric we do it here
152+
// so that we do not update timestamps for broken metrics
153+
info.timestamps[metricIndex][metricInfo.pos] = timestamp;
154+
// Update the position where to write the next metric
155+
metricInfo.pos = (metricInfo.pos + 1) % info.intMetrics[metricInfo.storeIdx].size();
156+
} break;
157+
case MetricType::String: {
158+
info.stringMetrics[metricInfo.storeIdx][metricInfo.pos] = stringValue;
159+
// Save the timestamp for the current metric we do it here
160+
// so that we do not update timestamps for broken metrics
161+
info.timestamps[metricIndex][metricInfo.pos] = timestamp;
162+
metricInfo.pos = (metricInfo.pos + 1) % info.stringMetrics[metricInfo.storeIdx].size();
148163
} break;
149164
case MetricType::Float: {
150-
floatValue = strtof(stringValue.str().c_str(), &ep);
165+
floatValue = strtof(valueMatch.str().c_str(), &ep);
151166
if (!ep || *ep != '\0') {
152167
return false;
153168
}
154169
info.floatMetrics[metricInfo.storeIdx][metricInfo.pos] = floatValue;
155170
info.max[metricIndex] = std::max(info.max[metricIndex], floatValue);
156171
info.min[metricIndex] = std::min(info.min[metricIndex], floatValue);
172+
// Save the timestamp for the current metric we do it here
173+
// so that we do not update timestamps for broken metrics
174+
info.timestamps[metricIndex][metricInfo.pos] = timestamp;
175+
metricInfo.pos = (metricInfo.pos + 1) % info.floatMetrics[metricInfo.storeIdx].size();
157176
} break;
158177
default:
159178
return false;
160179
break;
161180
};
162181

163-
// Save the timestamp for the current metric we do it here
164-
// so that we do not update timestamps for broken metrics
165-
info.timestamps[metricIndex][metricInfo.pos] = timestamp;
166-
// Update the position where to write the next metric
167-
metricInfo.pos = (metricInfo.pos + 1) % mod;
168182
return true;
169183
}
170184

@@ -189,6 +203,9 @@ std::ostream& operator<<(std::ostream& oss, MetricType const& val)
189203
case MetricType::Float:
190204
oss << "float";
191205
break;
206+
case MetricType::String:
207+
oss << "string";
208+
break;
192209
case MetricType::Int:
193210
oss << "float";
194211
break;

0 commit comments

Comments
 (0)