Home | History | Annotate | Download | only in perfprofd
      1 #ifndef SYSTEM_EXTRAS_PERFPROFD_MAP_UTILS_H_
      2 #define SYSTEM_EXTRAS_PERFPROFD_MAP_UTILS_H_
      3 
      4 #include <map>
      5 #include <set>
      6 
      7 #include <android-base/logging.h>
      8 
      9 namespace android {
     10 namespace perfprofd {
     11 
     12 template <typename T, typename U>
     13 decltype(static_cast<T*>(nullptr)->begin()) GetLeqIterator(T& map, U key) {
     14   if (map.empty()) {
     15     return map.end();
     16   }
     17   auto it = map.upper_bound(key);
     18   if (it == map.begin()) {
     19     return map.end();
     20   }
     21   --it;
     22   return it;
     23 }
     24 
     25 template <typename SymType, typename ValType>
     26 class RangeMap {
     27  public:
     28   struct AggregatedSymbol {
     29     SymType symbol;
     30     std::set<ValType> offsets;
     31     AggregatedSymbol(const SymType& sym, const ValType& offset) : symbol(sym) {
     32       offsets.insert(offset);
     33     }
     34   };
     35 
     36  public:
     37   void Insert(const SymType& sym, const ValType& val) {
     38     auto aggr_it = GetLeqIterator(map_, val);
     39     if (aggr_it == map_.end()) {
     40       // Maybe we need to extend the first one.
     41       if (!map_.empty()) {
     42         AggregatedSymbol& first = map_.begin()->second;
     43         CHECK_LT(val, map_.begin()->first);
     44         if (first.symbol == sym) {
     45           ExtendLeft(map_.begin(), val);
     46           return;
     47         }
     48       }
     49       // Nope, new entry needed.
     50       map_.emplace(val, AggregatedSymbol(sym, val));
     51       return;
     52     }
     53 
     54     AggregatedSymbol& maybe_match = aggr_it->second;
     55 
     56     if (maybe_match.symbol == sym) {
     57       // Same symbol, just insert. This is true for overlap as well as extension.
     58       maybe_match.offsets.insert(val);
     59       return;
     60     }
     61 
     62     // Is there overlap?
     63     if (*maybe_match.offsets.rbegin() < val) {
     64       // No. See if it can be merged with the next one.
     65       ++aggr_it;
     66       if (aggr_it != map_.end() && aggr_it->second.symbol == sym) {
     67         ExtendLeft(aggr_it, val);
     68         return;
     69       }
     70 
     71       // Just add a new symbol entry.
     72       map_.emplace(val, AggregatedSymbol(sym, val));
     73       return;
     74     }
     75 
     76     // OK, we have an overlapping non-symbol-equal AggregatedSymbol. Need to break
     77     // things up.
     78     AggregatedSymbol left(maybe_match.symbol, *maybe_match.offsets.begin());
     79     auto offset_it = maybe_match.offsets.begin();
     80     for (; *offset_it < val; ++offset_it) {
     81       left.offsets.insert(*offset_it);
     82     }
     83 
     84     if (*offset_it == val) {
     85       // This should not happen.
     86       LOG(ERROR) << "Unexpected overlap!";
     87       return;
     88     }
     89 
     90     AggregatedSymbol right(maybe_match.symbol, *offset_it);
     91     for (; offset_it != maybe_match.offsets.end(); ++offset_it) {
     92       right.offsets.insert(*offset_it);
     93     }
     94 
     95     map_.erase(aggr_it);
     96     map_.emplace(*left.offsets.begin(), std::move(left));
     97     map_.emplace(val, AggregatedSymbol(sym, val));
     98     map_.emplace(*right.offsets.begin(), std::move(right));
     99   }
    100 
    101   using RangeMapType = std::map<ValType, AggregatedSymbol>;
    102 
    103   typename RangeMapType::const_iterator begin() const {
    104     return map_.begin();
    105   }
    106   typename RangeMapType::const_iterator end() const {
    107     return map_.end();
    108   }
    109 
    110   bool empty() const {
    111     return map_.empty();
    112   }
    113 
    114  private:
    115   void ExtendLeft(typename RangeMapType::iterator it, const ValType& val) {
    116     CHECK(val < *it->second.offsets.begin());
    117     AggregatedSymbol copy = std::move(it->second);
    118     map_.erase(it);
    119     copy.offsets.insert(val);
    120     map_.emplace(val, std::move(copy));
    121   }
    122 
    123   RangeMapType map_;
    124 };
    125 
    126 }  // namespace perfprofd
    127 }  // namespace android
    128 
    129 #endif  // SYSTEM_EXTRAS_PERFPROFD_MAP_UTILS_H_
    130