summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xsrc/bp_gtest.cpp7
-rwxr-xr-xsrc/time_histogram.cpp242
-rwxr-xr-xsrc/time_histogram.h73
3 files changed, 155 insertions, 167 deletions
diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp
index 6085de76..7bb3da0c 100755
--- a/src/bp_gtest.cpp
+++ b/src/bp_gtest.cpp
@@ -2657,7 +2657,8 @@ public:
TEST_F(time_histogram, test_average) {
int i;
int j;
- for (j=0; j<10; j++) {
+ // Latency is calculated by low pass filter, so need to give it time to stabilize
+ for (j=0; j < 13; j++) {
for (i=0; i<100; i++) {
m_hist.Add(10e-6);
}
@@ -2667,8 +2668,8 @@ TEST_F(time_histogram, test_average) {
m_hist.update();
}
- EXPECT_GT(m_hist.get_average_latency(),7400.0);
- EXPECT_LT(m_hist.get_average_latency(),7600.0);
+ EXPECT_GT(m_hist.get_average_latency(), 5004);
+ EXPECT_LT(m_hist.get_average_latency(), 5005);
m_hist.Dump(stdout);
}
diff --git a/src/time_histogram.cpp b/src/time_histogram.cpp
index a6b98079..dd15c4be 100755
--- a/src/time_histogram.cpp
+++ b/src/time_histogram.cpp
@@ -1,13 +1,11 @@
-#include "time_histogram.h"
-#include <string.h>
-#include "utl_json.h"
/*
Hanoh Haim
+ Ido Barnea
Cisco Systems, Inc.
*/
/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
+Copyright (c) 2015-2016 Cisco Systems, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -22,182 +20,154 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
+#include <stdint.h>
+#include <string.h>
+#include "utl_json.h"
+#include "pal/linux/sanb_atomic.h"
+#include "time_histogram.h"
-
-
-void CTimeHistogram::Reset(){
- m_max_dt=0.0;
- m_cnt =0;
- m_high_cnt =0;
- m_max_win_dt=0;
- m_max_win_last_dt=0;
- m_average=0.0;
- memset(&m_max_ar[0],0,sizeof(m_max_ar));
- m_win_cnt=0;
+void CTimeHistogram::Reset() {
+ m_period_data[0].reset();
+ m_period_data[1].reset();
+ m_period = 0;
+ m_max_dt = 0;
+ m_average = 0;
+ memset(&m_max_ar[0],0,sizeof(m_max_ar));
+ m_win_cnt = 0;
int i;
int j;
- for (i=0;i<HISTOGRAM_SIZE; i++) {
- for (j=0; j<HISTOGRAM_SIZE_LOG;j++) {
- m_hcnt[j][i]=0;
+ for (i = 0; i < HISTOGRAM_SIZE; i++) {
+ for (j = 0; j < HISTOGRAM_SIZE_LOG; j++) {
+ m_hcnt[j][i] = 0;
}
}
- for (i=0;i<HISTOGRAM_SIZE; i++) {
- for (j=0; j<HISTOGRAM_SIZE_LOG;j++) {
- m_hcnt_shadow[j][i]=0;
- }
- }
- m_cnt_shadow=0;
- m_high_cnt_shadow=0;
}
-bool CTimeHistogram::Create(){
- m_min_delta =10.0/1000000.0;
+bool CTimeHistogram::Create() {
Reset();
+ m_min_delta =10.0/1000000.0;
return (true);
}
-void CTimeHistogram::Delete(){
+
+void CTimeHistogram::Delete() {
}
-bool CTimeHistogram::Add(dsec_t dt){
+bool CTimeHistogram::Add(dsec_t dt) {
+ CTimeHistogramPerPeriodData &period_elem = m_period_data[m_period];
- m_cnt++;
+ period_elem.inc_cnt();
if (dt < m_min_delta) {
return false;
}
- m_high_cnt++;
+ period_elem.inc_high_cnt();
- if ( m_max_dt < dt){
+ if ( m_max_dt < dt) {
m_max_dt = dt;
}
- if ( m_max_win_dt < dt){
- m_max_win_dt = dt;
- }
+ period_elem.update_max(dt);
- uint32_t d_10usec=(uint32_t)(dt*100000.0);
+ uint32_t d_10usec = (uint32_t)(dt*100000.0);
// 1 10-19 usec
//,2 -20-29 usec
//,3,
int j;
- for (j=0; j<HISTOGRAM_SIZE_LOG; j++) {
+ for (j = 0; j < HISTOGRAM_SIZE_LOG; j++) {
uint32_t low = d_10usec % 10;
uint32_t high = d_10usec / 10;
- if (high == 0 ) {
- if (low>0) {
- low=low-1;
+ if (high == 0) {
+ if (low > 0) {
+ low = low - 1;
}
m_hcnt[j][low]++;
break;
- }else{
- d_10usec =high;
+ } else {
+ d_10usec = high;
}
}
+ period_elem.update_sum(dt);
+
return true;
}
+void CTimeHistogram::update() {
+ // switch period, and get values for pervious period
+ CTimeHistogramPerPeriodData &period_elem = m_period_data[m_period];
+ uint8_t new_period;
-void CTimeHistogram::update(){
-
- m_max_ar[m_win_cnt]=m_max_win_dt;
- m_max_win_last_dt=m_max_win_dt;
- m_max_win_dt=0.0;
- m_win_cnt++;
- if (m_win_cnt==HISTOGRAM_QUEUE_SIZE) {
- m_win_cnt=0;
- }
- update_average();
-}
-
-double CTimeHistogram::get_cur_average(){
- int i,j;
- uint64_t d_cnt;
- uint64_t d_cnt_high;
-
- d_cnt = m_cnt - m_cnt_shadow;
- m_cnt_shadow =m_cnt;
- d_cnt_high = m_high_cnt - m_high_cnt_shadow;
- m_high_cnt_shadow =m_high_cnt;
-
- uint64_t low_events = d_cnt - d_cnt_high;
- uint64_t sum= low_events;
- double s = ((double)low_events * 5.0);
-
-
- for (j=0; j<HISTOGRAM_SIZE_LOG; j++) {
- for (i=0; i<HISTOGRAM_SIZE; i++) {
- uint64_t cnt=m_hcnt[j][i];
- if (cnt > 0 ) {
- uint64_t d= cnt - m_hcnt_shadow[j][i];
- sum += d;
- s+= ((double)d)*1.5*get_base_usec(j,i);
- m_hcnt_shadow[j][i] = cnt;
- }
- }
+ if (m_period == 0) {
+ new_period = 1;
+ } else {
+ new_period = 0;
}
-
- double c_average;
- if ( sum > 0 ) {
- c_average=s/(double)sum;
- }else{
- c_average=0.0;
+ m_period_data[new_period].reset();
+ sanb_smp_memory_barrier();
+ m_period = new_period;
+ sanb_smp_memory_barrier();
+
+ m_max_ar[m_win_cnt] = period_elem.get_max();
+ m_win_cnt++;
+ if (m_win_cnt == HISTOGRAM_QUEUE_SIZE) {
+ m_win_cnt = 0;
}
- return c_average;
+ update_average(period_elem);
}
-void CTimeHistogram::update_average(){
- double c_average=get_cur_average();
+void CTimeHistogram::update_average(CTimeHistogramPerPeriodData &period_elem) {
+ double c_average;
- // low pass filter
- m_average = 0.5*m_average + 0.5*c_average;
-}
+ if (period_elem.get_cnt() != 0)
+ c_average = period_elem.get_sum() / period_elem.get_cnt();
+ else
+ c_average = 0;
-dsec_t CTimeHistogram::get_total_average(){
- return (get_cur_average());
+ // low pass filter
+ m_average = 0.5 * m_average + 0.5 * c_average;
}
-dsec_t CTimeHistogram::get_average_latency(){
+dsec_t CTimeHistogram::get_average_latency() {
return (m_average);
}
-uint32_t CTimeHistogram::get_usec(dsec_t d){
+uint32_t CTimeHistogram::get_usec(dsec_t d) {
return (uint32_t)(d*1000000.0);
}
-void CTimeHistogram::DumpWinMax(FILE *fd){
-
- int i;
- uint32_t ci=m_win_cnt;
+void CTimeHistogram::DumpWinMax(FILE *fd) {
+ int i;
+ uint32_t ci=m_win_cnt;
- for (i=0; i<HISTOGRAM_QUEUE_SIZE-1; i++) {
- dsec_t d=get_usec(m_max_ar[ci]);
- ci++;
- if (ci>HISTOGRAM_QUEUE_SIZE-1) {
- ci=0;
- }
- fprintf(fd," %.0f ",d);
- }
+ for (i=0; i<HISTOGRAM_QUEUE_SIZE-1; i++) {
+ dsec_t d=get_usec(m_max_ar[ci]);
+ ci++;
+ if (ci>HISTOGRAM_QUEUE_SIZE-1) {
+ ci=0;
+ }
+ fprintf(fd," %.0f ",d);
+ }
}
-void CTimeHistogram::Dump(FILE *fd){
+void CTimeHistogram::Dump(FILE *fd) {
+ CTimeHistogramPerPeriodData &period_elem = m_period_data[get_read_period_index()];
+
fprintf (fd," min_delta : %lu usec \n", (ulong)get_usec(m_min_delta));
- fprintf (fd," cnt : %lu \n",m_cnt);
- fprintf (fd," high_cnt : %lu \n",m_high_cnt);
+ fprintf (fd," cnt : %lu \n", period_elem.get_cnt());
+ fprintf (fd," high_cnt : %lu \n", period_elem.get_high_cnt());
fprintf (fd," max_d_time : %lu usec\n", (ulong)get_usec(m_max_dt));
- //fprintf (fd," average : %.0f usec\n", get_total_average());
fprintf (fd," sliding_average : %.0f usec\n", get_average_latency());
- fprintf (fd," precent : %.1f %%\n",(100.0*(double)m_high_cnt/(double)m_cnt));
+ fprintf (fd," precent : %.1f %%\n",(100.0*(double)period_elem.get_high_cnt()/(double)period_elem.get_cnt()));
fprintf (fd," histogram \n");
fprintf (fd," -----------\n");
int i;
int j;
int base=10;
- for (j=0; j<HISTOGRAM_SIZE_LOG; j++) {
- for (i=0; i<HISTOGRAM_SIZE; i++) {
- if (m_hcnt[j][i] >0 ) {
+ for (j = 0; j < HISTOGRAM_SIZE_LOG; j++) {
+ for (i = 0; i < HISTOGRAM_SIZE; i++) {
+ if (m_hcnt[j][i] > 0) {
fprintf (fd," h[%u] : %llu \n",(base*(i+1)),(unsigned long long)m_hcnt[j][i]);
}
}
@@ -210,7 +180,8 @@ void CTimeHistogram::Dump(FILE *fd){
*/
-void CTimeHistogram::dump_json(std::string name,std::string & json ){
+void CTimeHistogram::dump_json(std::string name,std::string & json ) {
+ CTimeHistogramPerPeriodData &period_elem = m_period_data[get_read_period_index()];
char buff[200];
if (name != "")
sprintf(buff,"\"%s\":{",name.c_str());
@@ -218,37 +189,32 @@ void CTimeHistogram::dump_json(std::string name,std::string & json ){
sprintf(buff,"{");
json+=std::string(buff);
- json+=add_json("min_usec",get_usec(m_min_delta));
- json+=add_json("max_usec",get_usec(m_max_dt));
- json+=add_json("high_cnt",m_high_cnt);
- json+=add_json("cnt",m_cnt);
- //json+=add_json("t_avg",get_total_average());
- json+=add_json("s_avg",get_average_latency());
+ json += add_json("min_usec", get_usec(m_min_delta));
+ json += add_json("max_usec", get_usec(m_max_dt));
+ json += add_json("high_cnt", period_elem.get_high_cnt());
+ json += add_json("cnt", period_elem.get_cnt());
+ json+=add_json("s_avg", get_average_latency());
int i;
int j;
uint32_t base=10;
json+=" \"histogram\": [";
- bool first=true;
- for (j=0; j<HISTOGRAM_SIZE_LOG; j++) {
- for (i=0; i<HISTOGRAM_SIZE; i++) {
- if (m_hcnt[j][i] >0 ) {
- if ( first ){
- first=false;
+ bool first=true;
+ for (j = 0; j < HISTOGRAM_SIZE_LOG; j++) {
+ for (i = 0; i < HISTOGRAM_SIZE; i++) {
+ if (m_hcnt[j][i] > 0) {
+ if ( first ) {
+ first = false;
}else{
- json+=",";
+ json += ",";
}
- json+="{";
- json+=add_json("key",(base*(i+1)));
- json+=add_json("val",m_hcnt[j][i],true);
- json+="}";
+ json += "{";
+ json += add_json("key",(base*(i+1)));
+ json += add_json("val",m_hcnt[j][i],true);
+ json += "}";
}
}
- base=base*10;
+ base = base * 10;
}
json+=" ] } ,";
-
}
-
-
-
diff --git a/src/time_histogram.h b/src/time_histogram.h
index e733c65f..9bdf2c93 100755
--- a/src/time_histogram.h
+++ b/src/time_histogram.h
@@ -2,11 +2,12 @@
#define C_TIME_HISTOGRAM_H
/*
Hanoh Haim
+ Ido Barnea
Cisco Systems, Inc.
*/
/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
+Copyright (c) 2015-2016 Cisco Systems, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -29,6 +30,35 @@ limitations under the License.
#include "mbuf.h"
#include <string>
+class CTimeHistogramPerPeriodData {
+ public:
+ void reset() {
+ m_sum = 0;
+ m_cnt = 0;
+ m_cnt_high = 0;
+ m_max = 0;
+ }
+ void inc_cnt() {m_cnt++;}
+ void inc_high_cnt() {m_cnt_high++;}
+ void update_max(dsec_t dt) {
+ if (dt > m_max)
+ m_max = dt;
+ }
+ void update_sum(dsec_t dt) {
+ m_sum += dt * 1000000;
+ }
+ inline uint64_t get_sum() {return m_sum;}
+ inline uint64_t get_cnt() {return m_cnt;}
+ inline uint64_t get_high_cnt() {return m_cnt_high;}
+ inline dsec_t get_max() {return m_max;}
+ inline dsec_t get_max_usec() {return m_max * 1000000;}
+
+ private:
+ uint64_t m_sum; // Sum of samples
+ uint64_t m_cnt; // Number of samples
+ uint64_t m_cnt_high; // Number of samples above configured threshold
+ dsec_t m_max; // Max sample
+};
class CTimeHistogram {
public:
@@ -43,50 +73,41 @@ public:
bool Add(dsec_t dt);
void Dump(FILE *fd);
void DumpWinMax(FILE *fd);
- /* should be called each 1 sec */
+ /* should be called once each sampling period */
void update();
dsec_t get_average_latency();
/* get average of total data */
- dsec_t get_total_average();
-
-
dsec_t get_max_latency(){
return (get_usec(m_max_dt));
}
-
dsec_t get_max_latency_last_update(){
- return ( get_usec(m_max_win_last_dt) );
+ CTimeHistogramPerPeriodData &period_elem = m_period_data[get_read_period_index()];
+ return period_elem.get_max_usec();
}
-
void dump_json(std::string name,std::string & json );
-
private:
uint32_t get_usec(dsec_t d);
double get_cur_average();
- void update_average();
-
- double get_base_usec(int j,int i){
- double base=pow(10.0,(double)j+1.0);
- return ( base * ((double)i+1.0) );
+ void update_average(CTimeHistogramPerPeriodData &period_elem);
+ inline uint8_t get_read_period_index() {
+ if (m_period == 0)
+ return 1;
+ else
+ return 0;
}
-public:
+private:
dsec_t m_min_delta;/* set to 10usec*/
- uint64_t m_cnt;
- uint64_t m_high_cnt;
- dsec_t m_max_dt;
- dsec_t m_max_win_dt;
- dsec_t m_max_win_last_dt;
+ // One element collects data for current period, other is saved for sending report.
+ // Each period we switch between the two
+ CTimeHistogramPerPeriodData m_period_data[2];
+ uint8_t m_period; // 0 or 1 according to m_period_data element we currently use
+ dsec_t m_max_dt; // Total maximum latency
dsec_t m_average; /* moving average */
-
uint32_t m_win_cnt;
- dsec_t m_max_ar[HISTOGRAM_QUEUE_SIZE];
-
+ dsec_t m_max_ar[HISTOGRAM_QUEUE_SIZE]; // Array of maximum latencies for previous periods
uint64_t m_hcnt[HISTOGRAM_SIZE_LOG][HISTOGRAM_SIZE] __rte_cache_aligned ;
- uint64_t m_hcnt_shadow[HISTOGRAM_SIZE_LOG][HISTOGRAM_SIZE] __rte_cache_aligned ; // this this contorl side
- uint64_t m_cnt_shadow;
- uint64_t m_high_cnt_shadow;
};
#endif