2017-05-26 04:48:44 +08:00
/*
* Stats . h
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013 - 2018 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 .
*/
# ifndef FLOW_STATS_H
# define FLOW_STATS_H
# pragma once
// Yet another performance statistics interface
/*
struct MyCounters {
CounterCollection cc ;
Counter foo , bar , baz ;
MyCounters ( ) : foo ( " foo " , cc ) , bar ( " bar " , cc ) , baz ( " baz " , cc ) { }
} ;
*/
2018-08-11 05:36:45 +08:00
# include <cstdint>
# include <cstddef>
2018-10-20 01:30:13 +08:00
# include "flow/flow.h"
# include "flow/TDMetric.actor.h"
2017-05-26 04:48:44 +08:00
2018-12-01 02:46:04 +08:00
struct TimedRequest {
double requestTime ;
TimedRequest ( ) {
requestTime = timer ( ) ;
}
} ;
2017-05-26 04:48:44 +08:00
struct ICounter {
// All counters have a name and value
virtual std : : string const & getName ( ) const = 0 ;
virtual int64_t getValue ( ) const = 0 ;
// Counters may also have rate and roughness
virtual bool hasRate ( ) const = 0 ;
virtual double getRate ( ) const = 0 ;
virtual bool hasRoughness ( ) const = 0 ;
virtual double getRoughness ( ) const = 0 ;
virtual void resetInterval ( ) = 0 ;
virtual void remove ( ) { }
} ;
struct CounterCollection {
CounterCollection ( std : : string name , std : : string id = std : : string ( ) ) : name ( name ) , id ( id ) { }
std : : vector < struct ICounter * > counters , counters_to_remove ;
~ CounterCollection ( ) { for ( auto c : counters_to_remove ) c - > remove ( ) ; }
std : : string name ;
std : : string id ;
} ;
2018-12-01 02:46:04 +08:00
struct Counter : ICounter , NonCopyable {
2017-05-26 04:48:44 +08:00
public :
typedef int64_t Value ;
Counter ( std : : string const & name , CounterCollection & collection ) ;
void operator + = ( Value delta ) ;
void operator + + ( ) { * this + = 1 ; }
void clear ( ) ;
void resetInterval ( ) ;
std : : string const & getName ( ) const { return name ; }
Value getIntervalDelta ( ) const { return interval_delta ; }
Value getValue ( ) const { return interval_start_value + interval_delta ; }
double getRate ( ) const ; // dValue / dt
double getRoughness ( ) const ; // value deltas come in "clumps" of this many ( 1 = periodic, 2 = poisson, 10 = periodic clumps of 10 (nearly) simultaneous delta )
bool hasRate ( ) const { return true ; }
bool hasRoughness ( ) const { return true ; }
private :
std : : string name ;
double interval_start , last_event , interval_sq_time ;
Value interval_delta , interval_start_value ;
Int64MetricHandle metric ;
} ;
template < class F >
2018-12-01 02:46:04 +08:00
struct SpecialCounter : ICounter , FastAllocated < SpecialCounter < F > > , NonCopyable {
2017-05-26 04:48:44 +08:00
SpecialCounter ( CounterCollection & collection , std : : string const & name , F & & f ) : name ( name ) , f ( f ) { collection . counters . push_back ( this ) ; collection . counters_to_remove . push_back ( this ) ; }
virtual void remove ( ) { delete this ; }
virtual std : : string const & getName ( ) const { return name ; }
virtual int64_t getValue ( ) const { return f ( ) ; }
virtual void resetInterval ( ) { }
virtual bool hasRate ( ) const { return false ; }
virtual double getRate ( ) const { throw internal_error ( ) ; }
virtual bool hasRoughness ( ) const { return false ; }
virtual double getRoughness ( ) const { throw internal_error ( ) ; }
std : : string name ;
F f ;
} ;
template < class F >
static void specialCounter ( CounterCollection & collection , std : : string const & name , F & & f ) { new SpecialCounter < F > ( collection , name , std : : move ( f ) ) ; }
2019-02-08 05:39:22 +08:00
Future < Void > traceCounters ( std : : string const & traceEventName , UID const & traceEventID , double const & interval , CounterCollection * const & counters , std : : string const & trackLatestName = std : : string ( ) ) ;
2018-12-01 02:46:04 +08:00
class LatencyBands {
public :
2019-02-08 05:39:22 +08:00
LatencyBands ( std : : string name , UID id , double loggingInterval ) : name ( name ) , id ( id ) , loggingInterval ( loggingInterval ) , cc ( nullptr ) , filteredCount ( nullptr ) { }
2018-12-01 02:46:04 +08:00
void addThreshold ( double value ) {
if ( value > 0 & & bands . count ( value ) = = 0 ) {
2019-01-19 08:18:34 +08:00
if ( bands . size ( ) = = 0 ) {
2019-02-08 05:39:22 +08:00
ASSERT ( ! cc & & ! filteredCount ) ;
cc = new CounterCollection ( name , id . toString ( ) ) ;
logger = traceCounters ( name , id , loggingInterval , cc , id . toString ( ) + " / " + name ) ;
filteredCount = new Counter ( " Filtered " , * cc ) ;
2019-01-19 08:18:34 +08:00
insertBand ( std : : numeric_limits < double > : : infinity ( ) ) ;
}
insertBand ( value ) ;
2018-12-01 02:46:04 +08:00
}
}
void addMeasurement ( double measurement , bool filtered = false ) {
2019-01-19 08:18:34 +08:00
if ( filtered & & filteredCount ) {
+ + ( * filteredCount ) ;
}
else if ( bands . size ( ) > 0 ) {
auto itr = bands . upper_bound ( measurement ) ;
ASSERT ( itr ! = bands . end ( ) ) ;
+ + ( * itr - > second ) ;
2018-12-01 02:46:04 +08:00
}
}
2019-01-19 08:18:34 +08:00
void clearBands ( ) {
2019-02-08 05:39:22 +08:00
logger = Void ( ) ;
2019-01-19 08:18:34 +08:00
for ( auto itr : bands ) {
delete itr . second ;
2018-12-01 02:46:04 +08:00
}
2019-01-19 08:18:34 +08:00
bands . clear ( ) ;
delete filteredCount ;
2019-02-08 05:39:22 +08:00
delete cc ;
filteredCount = nullptr ;
cc = nullptr ;
2019-01-19 08:18:34 +08:00
}
~ LatencyBands ( ) {
clearBands ( ) ;
2018-12-01 02:46:04 +08:00
}
private :
std : : map < double , Counter * > bands ;
2019-01-19 08:18:34 +08:00
Counter * filteredCount ;
2018-12-01 02:46:04 +08:00
std : : string name ;
2019-02-08 05:39:22 +08:00
UID id ;
double loggingInterval ;
CounterCollection * cc ;
Future < Void > logger ;
2019-01-19 08:18:34 +08:00
void insertBand ( double value ) {
2019-02-08 05:39:22 +08:00
bands . insert ( std : : make_pair ( value , new Counter ( format ( " Band%f " , value ) , * cc ) ) ) ;
2019-01-19 08:18:34 +08:00
}
2018-12-01 02:46:04 +08:00
} ;
2018-08-11 05:36:45 +08:00
# endif