2017-05-26 04:48:44 +08:00
|
|
|
/*
|
|
|
|
* Stats.actor.cpp
|
|
|
|
*
|
|
|
|
* This source file is part of the FoundationDB open source project
|
|
|
|
*
|
2022-03-22 04:36:23 +08:00
|
|
|
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2020-07-10 07:39:15 +08:00
|
|
|
#include "fdbrpc/Stats.h"
|
2022-09-26 07:41:29 +08:00
|
|
|
#include "flow/TDMetric.actor.h"
|
2019-02-18 06:39:16 +08:00
|
|
|
#include "flow/actorcompiler.h" // has to be last include
|
2022-09-26 07:41:29 +08:00
|
|
|
#include <string>
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
Counter::Counter(std::string const& name, CounterCollection& collection)
|
2022-09-24 03:32:38 +08:00
|
|
|
: IMetric(name), interval_start(0), last_event(0), interval_sq_time(0), roughness_interval_start(0),
|
|
|
|
interval_delta(0), interval_start_value(0) {
|
2022-10-26 01:17:15 +08:00
|
|
|
metric.init(collection.getName() + "." + (char)toupper(name.at(0)) + name.substr(1), collection.getId());
|
|
|
|
collection.addCounter(this);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Counter::operator+=(Value delta) {
|
|
|
|
if (!delta)
|
|
|
|
return; //< Otherwise last_event will be reset
|
|
|
|
interval_delta += delta;
|
|
|
|
auto t = now();
|
|
|
|
auto elapsed = t - last_event;
|
|
|
|
interval_sq_time += elapsed * elapsed;
|
|
|
|
last_event = t;
|
|
|
|
|
|
|
|
metric += delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
double Counter::getRate() const {
|
|
|
|
double elapsed = now() - interval_start;
|
|
|
|
return elapsed > 0 ? interval_delta / elapsed : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
double Counter::getRoughness() const {
|
2020-10-20 04:40:16 +08:00
|
|
|
double elapsed = last_event - roughness_interval_start;
|
2017-05-26 04:48:44 +08:00
|
|
|
if (elapsed == 0) {
|
2020-02-27 08:39:13 +08:00
|
|
|
return -1;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2020-02-27 08:39:13 +08:00
|
|
|
// If we have time interval samples t in T, and let:
|
2020-02-26 00:45:51 +08:00
|
|
|
// n = size(T) = interval_delta
|
|
|
|
// m = mean(T) = elapsed / interval_delta
|
|
|
|
// v = sum(t^2) for t in T = interval_sq_time
|
|
|
|
//
|
|
|
|
// The formula below is: (v/(m*n)) / m - 1
|
|
|
|
// This is equivalent to (v/n - m^2) / m^2 = Variance(T)/m^2
|
|
|
|
// Variance(T)/m^2 is equal to Variance(t/m) for t in T
|
2017-05-26 04:48:44 +08:00
|
|
|
double delay = interval_sq_time / elapsed;
|
2020-02-26 00:45:51 +08:00
|
|
|
return delay * interval_delta / elapsed - 1;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Counter::resetInterval() {
|
|
|
|
interval_start_value += interval_delta;
|
|
|
|
interval_delta = 0;
|
|
|
|
interval_sq_time = 0;
|
|
|
|
interval_start = now();
|
2020-02-26 00:45:51 +08:00
|
|
|
if (last_event == 0) {
|
|
|
|
last_event = interval_start;
|
|
|
|
}
|
|
|
|
roughness_interval_start = last_event;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Counter::clear() {
|
|
|
|
resetInterval();
|
|
|
|
interval_start_value = 0;
|
|
|
|
|
|
|
|
metric = 0;
|
|
|
|
}
|
|
|
|
|
2022-09-26 07:41:29 +08:00
|
|
|
void Counter::flush(MetricBatch& batch) {
|
|
|
|
Value val = getValue();
|
|
|
|
std::string msg = create_statsd_message(name, StatsDMetric::COUNTER, std::to_string(val));
|
|
|
|
if (!batch.statsd_message.empty()) {
|
|
|
|
batch.statsd_message += "\n";
|
|
|
|
}
|
|
|
|
batch.statsd_message += msg;
|
|
|
|
}
|
2022-09-24 03:32:38 +08:00
|
|
|
|
2019-07-09 05:01:04 +08:00
|
|
|
void CounterCollection::logToTraceEvent(TraceEvent& te) const {
|
|
|
|
for (ICounter* c : counters) {
|
|
|
|
te.detail(c->getName().c_str(), c);
|
|
|
|
c->resetInterval();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-26 01:17:15 +08:00
|
|
|
class CounterCollectionImpl {
|
|
|
|
public:
|
|
|
|
ACTOR static Future<Void> traceCounters(CounterCollection* counters,
|
|
|
|
std::string traceEventName,
|
|
|
|
UID traceEventID,
|
|
|
|
double interval,
|
|
|
|
std::string trackLatestName,
|
|
|
|
std::function<void(TraceEvent&)> decorator) {
|
|
|
|
wait(delay(0)); // Give an opportunity for all members used in special counters to be initialized
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2022-10-26 01:17:15 +08:00
|
|
|
for (ICounter* c : counters->counters)
|
|
|
|
c->resetInterval();
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2022-10-26 01:17:15 +08:00
|
|
|
state Reference<EventCacheHolder> traceEventHolder;
|
|
|
|
if (!trackLatestName.empty()) {
|
|
|
|
traceEventHolder = makeReference<EventCacheHolder>(trackLatestName);
|
|
|
|
}
|
2021-09-22 05:03:14 +08:00
|
|
|
|
2022-10-26 01:17:15 +08:00
|
|
|
state double last_interval = now();
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2022-10-26 01:17:15 +08:00
|
|
|
loop {
|
|
|
|
TraceEvent te(traceEventName.c_str(), traceEventID);
|
|
|
|
te.detail("Elapsed", now() - last_interval);
|
2019-07-09 05:01:04 +08:00
|
|
|
|
2022-10-26 01:17:15 +08:00
|
|
|
counters->logToTraceEvent(te);
|
|
|
|
decorator(te);
|
2019-07-09 05:01:04 +08:00
|
|
|
|
2022-10-26 01:17:15 +08:00
|
|
|
if (!trackLatestName.empty()) {
|
|
|
|
te.trackLatest(traceEventHolder->trackingKey);
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2022-10-26 01:17:15 +08:00
|
|
|
last_interval = now();
|
|
|
|
wait(delay(interval, TaskPriority::FlushTrace));
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2022-10-26 01:17:15 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
Future<Void> CounterCollection::traceCounters(std::string const& traceEventName,
|
|
|
|
UID traceEventID,
|
|
|
|
double interval,
|
|
|
|
std::string const& trackLatestName,
|
|
|
|
std::function<void(TraceEvent&)> const& decorator) {
|
|
|
|
return CounterCollectionImpl::traceCounters(
|
|
|
|
this, traceEventName, traceEventID, interval, trackLatestName, decorator);
|
2019-02-18 06:39:16 +08:00
|
|
|
}
|
2022-10-26 06:17:53 +08:00
|
|
|
|
|
|
|
void LatencyBands::insertBand(double value) {
|
|
|
|
bands.emplace(std::make_pair(value, std::make_unique<Counter>(format("Band%f", value), *cc)));
|
|
|
|
}
|
|
|
|
|
2022-10-26 08:10:59 +08:00
|
|
|
FDB_DEFINE_BOOLEAN_PARAM(Filtered);
|
|
|
|
|
2022-10-26 06:22:24 +08:00
|
|
|
LatencyBands::LatencyBands(std::string const& name,
|
|
|
|
UID id,
|
|
|
|
double loggingInterval,
|
|
|
|
std::function<void(TraceEvent&)> const& decorator)
|
|
|
|
: name(name), id(id), loggingInterval(loggingInterval), decorator(decorator) {}
|
2022-10-26 06:17:53 +08:00
|
|
|
|
|
|
|
void LatencyBands::addThreshold(double value) {
|
|
|
|
if (value > 0 && bands.count(value) == 0) {
|
|
|
|
if (bands.size() == 0) {
|
|
|
|
ASSERT(!cc && !filteredCount);
|
|
|
|
cc = std::make_unique<CounterCollection>(name, id.toString());
|
|
|
|
logger = cc->traceCounters(name, id, loggingInterval, id.toString() + "/" + name, decorator);
|
|
|
|
filteredCount = std::make_unique<Counter>("Filtered", *cc);
|
|
|
|
insertBand(std::numeric_limits<double>::infinity());
|
|
|
|
}
|
|
|
|
|
|
|
|
insertBand(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-26 08:10:59 +08:00
|
|
|
void LatencyBands::addMeasurement(double measurement, int count, Filtered filtered) {
|
2022-10-26 06:17:53 +08:00
|
|
|
if (filtered && filteredCount) {
|
2022-10-26 08:10:59 +08:00
|
|
|
(*filteredCount) += count;
|
2022-10-26 06:17:53 +08:00
|
|
|
} else if (bands.size() > 0) {
|
|
|
|
auto itr = bands.upper_bound(measurement);
|
|
|
|
ASSERT(itr != bands.end());
|
2022-10-26 08:10:59 +08:00
|
|
|
(*itr->second) += count;
|
2022-10-26 06:17:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LatencyBands::clearBands() {
|
|
|
|
logger = Void();
|
|
|
|
bands.clear();
|
|
|
|
filteredCount.reset();
|
|
|
|
cc.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
LatencyBands::~LatencyBands() {
|
|
|
|
clearBands();
|
|
|
|
}
|