diff options
-rwxr-xr-x | src/bp_gtest.cpp | 7 | ||||
-rwxr-xr-x | src/time_histogram.cpp | 242 | ||||
-rwxr-xr-x | src/time_histogram.h | 73 |
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 |