Home | History | Annotate | Download | only in tsan
      1 /* Copyright (c) 2008-2010, Google Inc.
      2  * All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Neither the name of Google Inc. nor the names of its
     11  * contributors may be used to endorse or promote products derived from
     12  * this software without specific prior written permission.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 // This file is part of ThreadSanitizer, a dynamic data race detector.
     28 // Author: Konstantin Serebryany.
     29 // Information about one TRACE (single-entry-multiple-exit region of code).
     30 #ifndef TS_TRACE_INFO_
     31 #define TS_TRACE_INFO_
     32 
     33 #include "ts_util.h"
     34 // Information about one Memory Operation.
     35 //
     36 // A memory access is represented by mop[idx] = {pc,size,is_write}
     37 // which is computed at instrumentation time and {actual_address} computed
     38 // at run-time. The instrumentation insn looks like
     39 //  tleb[idx] = actual_address
     40 // The create_sblock field tells if we want to remember the stack trace
     41 // which corresponds to this Mop (i.e. create an SBLOCK).
     42 struct MopInfo {
     43  public:
     44   MopInfo(uintptr_t pc, size_t size, bool is_write, bool create_sblock) {
     45     DCHECK(sizeof(*this) == 8);
     46     pc_ = pc;
     47     if (size > 16) size = 16; // some instructions access more than 16 bytes.
     48     size_minus1_ = size - 1;
     49     is_write_ = is_write;
     50     create_sblock_ = create_sblock;
     51 
     52     DCHECK(size != 0);
     53     DCHECK(this->size() == size);
     54     DCHECK(this->is_write() == is_write);
     55     DCHECK(this->create_sblock() == create_sblock);
     56   }
     57 
     58   MopInfo() {
     59     DCHECK(sizeof(*this) == 8);
     60     memset(this, 0, sizeof(*this));
     61   }
     62 
     63   uintptr_t pc()            { return pc_; };
     64   size_t    size()          { return size_minus1_ + 1; }
     65   bool      is_write()      { return is_write_; }
     66   bool      create_sblock() { return create_sblock_; }
     67 
     68  private:
     69   uint64_t  pc_           :58;  // 48 bits is enough for pc, even on x86-64.
     70   uint64_t  create_sblock_ :1;
     71   uint64_t  is_write_      :1;
     72   uint64_t  size_minus1_   :4;  // 0..15
     73 };
     74 
     75 // ---------------- Lite Race ------------------
     76 // Experimental!
     77 //
     78 // The idea was first introduced in LiteRace:
     79 // http://www.cs.ucla.edu/~dlmarino/pubs/pldi09.pdf
     80 // Instead of analyzing all memory accesses, we do sampling.
     81 // For each trace (single-enry muliple-exit region) we maintain a counter of
     82 // executions. If a trace has been executed more than a certain threshold, we
     83 // start skipping this trace sometimes.
     84 // The LiteRace paper suggests several strategies for sampling, including
     85 // thread-local counters. Having thread local counters for all threads is too
     86 // expensive, so we have kLiteRaceNumTids arrays of counters and use
     87 // the array (tid % 8).
     88 //
     89 // sampling_rate indicates the level of sampling.
     90 // 0 means no sampling.
     91 // 1 means handle *almost* all accesses.
     92 // ...
     93 // 31 means very aggressive sampling (skip a lot of accesses).
     94 
     95 //
     96 // Note: ANNOTATE_PUBLISH_MEMORY() does not work with sampling... :(
     97 
     98 struct LiteRaceCounters {
     99   uint32_t counter;
    100   int32_t num_to_skip;
    101 };
    102 
    103 struct TraceInfoPOD {
    104   enum { kLiteRaceNumTids = 8 };
    105   enum { kLiteRaceStorageSize = 8 };
    106   typedef LiteRaceCounters LiteRaceStorage[kLiteRaceNumTids][kLiteRaceStorageSize];
    107 
    108   size_t n_mops_;
    109   size_t pc_;
    110   size_t counter_;
    111   LiteRaceStorage *literace_storage;
    112   int32_t storage_index;
    113   MopInfo mops_[1];
    114 };
    115 
    116 // An instance of this class is created for each TRACE (SEME region)
    117 // during instrumentation.
    118 class TraceInfo : public TraceInfoPOD {
    119  public:
    120   static TraceInfo *NewTraceInfo(size_t n_mops, uintptr_t pc);
    121   void DeleteTraceInfo(TraceInfo *trace_info) {
    122     delete [] (uintptr_t*)trace_info;
    123   }
    124   MopInfo *GetMop(size_t i) {
    125     DCHECK(i < n_mops_);
    126     return &mops_[i];
    127   }
    128 
    129   size_t n_mops() const { return n_mops_; }
    130   size_t pc()     const { return pc_; }
    131   size_t &counter()     { return counter_; }
    132   MopInfo *mops()       { return mops_; }
    133 
    134   static void PrintTraceProfile();
    135 
    136   INLINE bool LiteRaceSkipTraceQuickCheck(uintptr_t tid_modulo_num) {
    137     DCHECK(tid_modulo_num < kLiteRaceNumTids);
    138     // Check how may accesses are left to skip. Racey, but ok.
    139     LiteRaceCounters *counters =
    140         &((*literace_storage)[tid_modulo_num][storage_index]);
    141     int32_t num_to_skip = --counters->num_to_skip;
    142     if (num_to_skip > 0) {
    143       return true;
    144     }
    145     return false;
    146   }
    147 
    148   INLINE void LiteRaceUpdate(uintptr_t tid_modulo_num, uint32_t sampling_rate) {
    149     DCHECK(sampling_rate < 32);
    150     DCHECK(sampling_rate > 0);
    151     LiteRaceCounters *counters =
    152         &((*literace_storage)[tid_modulo_num][storage_index]);
    153     uint32_t cur_counter = counters->counter;
    154     // The bigger the counter the bigger the number of skipped accesses.
    155     int32_t next_num_to_skip = (cur_counter >> (32 - sampling_rate)) + 1;
    156     counters->num_to_skip = next_num_to_skip;
    157     counters->counter = cur_counter + next_num_to_skip;
    158 
    159   }
    160 
    161   // TODO(glider): get rid of this.
    162   INLINE void LLVMLiteRaceUpdate(uintptr_t tid_modulo_num,
    163                                  uint32_t sampling_rate) {
    164     LiteRaceUpdate(tid_modulo_num, sampling_rate);
    165   }
    166 
    167   // This is all racey, but ok.
    168   INLINE bool LiteRaceSkipTrace(uint32_t tid_modulo_num,
    169                                 uint32_t sampling_rate) {
    170     if (LiteRaceSkipTraceQuickCheck(tid_modulo_num)) return true;
    171     LiteRaceUpdate(tid_modulo_num, sampling_rate);
    172     return false;
    173   }
    174 
    175   INLINE bool LiteRaceSkipTraceRealTid(uint32_t tid, uint32_t sampling_rate) {
    176     return LiteRaceSkipTrace(tid % kLiteRaceNumTids, sampling_rate);
    177   }
    178 
    179  private:
    180   static size_t id_counter_;
    181   static vector<TraceInfo*> *g_all_traces;
    182 
    183   TraceInfo() : TraceInfoPOD() { }
    184 };
    185 
    186 // end. {{{1
    187 #endif  // TS_TRACE_INFO_
    188 // vim:shiftwidth=2:softtabstop=2:expandtab:tw=80
    189