Project

General

Profile

Bug #25211

Updated by Kefu Chai over 5 years ago

when we call PerfCounters::inc() and read_avg() at the same time, maybe the result is not what we want. 

 show the code here 
 <pre><code class="cpp"> 
 void PerfCounters::inc(int idx, uint64_t amt) 
 { 
   if (!m_cct->_conf->perf) 
     return; 

   assert(idx > m_lower_bound); 
   assert(idx < m_upper_bound); 
   perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]); 
   if (!(data.type & PERFCOUNTER_U64)) 
     return; 
   if (data.type & PERFCOUNTER_LONGRUNAVG) { 
     data.avgcount.inc(); 
     data.u64.add(amt); 
     data.avgcount2.inc(); 
   } else { 
     data.u64.add(amt); 
   } 
 } 
 </code></pre> 

 <pre><code class="cpp"> 
 /// read <sum, count> safely 
     pair<uint64_t,uint64_t> read_avg() const { 
       uint64_t sum, count; 
       do { 
         count = avgcount.read(); 
         sum = u64.read(); 
       } while (avgcount2.read() != count); 
       return make_pair(sum, count); 
     } 
 </code></pre> 

 ok, here is the problem, if we have two thread: 
 assume data.u64 = s; data.avgcount = data.avgcount2 
 <pre> 
      thread1 : read               |      thread2: inc(v) 
                                 | 
      count     = (avgcount=n)       (avgcount2=n)      |     
                                 |      avgcount avgcount2 = (n+1) 
                                 |      u64 = (s+v) 
      sum = (s+v)                  | 
      count      == avgcount2 == n |     
                                 |      avgcount2 = (n+1) 
                                \/     
 </pre>  
 we get (s+v, n), but correct result is (s+v, n+1) 

 same problem: 
 <pre> 
      thread1 : read_avg()                thread2: inc(v) 

                                   |      avgcount avgcount2 = (n+1) 
                                   |     
      count = (avgcount=(n+1))       (avgcount2=(n+1))      |     
      sum = (data.u64 = s)           | 
                                   |      data.u64 = (s+v)    
                                   |      avgcount2 = (n+1) 
      count      == avgcount2 == n+1 | 
                                   \/ 
 </pre>   
                                  
 we get (s, n+1), but correct result is (s+v, n+1) 

 we should swap the position of avgcount and avgcount2: 
 <pre><code class="cpp"> 
 /// read <sum, count> safely 
     pair<uint64_t,uint64_t> read_avg() const { 
       uint64_t sum, count; 
       do { 
         count = avgcount2.read();       // read avgcount2 first instead of avgcount 
         sum = u64.read(); 
       } while (avgcount.read() != count); 
       return make_pair(sum, count); 
     } 
 </code></pre>

Back