1 /*
   2  * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #ifndef SHARE_GC_G1_G1REGIONMARKSTATSCACHE_HPP
  26 #define SHARE_GC_G1_G1REGIONMARKSTATSCACHE_HPP
  27 
  28 #include "memory/allocation.hpp"
  29 #include "utilities/debug.hpp"
  30 #include "utilities/globalDefinitions.hpp"
  31 #include "utilities/pair.hpp"
  32 
  33 // Per-Region statistics gathered during marking.
  34 //
  35 // This includes
  36 // * the number of live words gathered during marking for the area from bottom
  37 // to ntams. This is an exact measure.
  38 // The code corrects later for the live data between ntams and top.
  39 struct G1RegionMarkStats {
  40   size_t _live_words;
  41 
  42   // Clear all members.
  43   void clear() {
  44     _live_words = 0;
  45   }
  46   // Clear all members after a marking overflow. Nothing to do as the live words
  47   // are updated by the atomic mark. We do not remark objects after overflow.
  48   void clear_during_overflow() {
  49   }
  50 
  51   bool is_clear() const { return _live_words == 0; }
  52 };
  53 
  54 // Per-marking thread cache for the region mark statistics.
  55 //
  56 // Each cache is a larg'ish map of region-idx -> G1RegionMarkStats entries that cache
  57 // currently gathered statistics; entries are evicted to the global statistics array
  58 // on every collision. This minimizes synchronization overhead which would be required
  59 // every time statistics change, as marking is very localized.
  60 // The map entry number is a power of two to allow simple and fast hashing using
  61 // logical and.
  62 class G1RegionMarkStatsCache {
  63 private:
  64   // The array of statistics entries to evict to; the global array.
  65   G1RegionMarkStats* _target;
  66 
  67   // An entry of the statistics cache.
  68   struct G1RegionMarkStatsCacheEntry {
  69     uint _region_idx;
  70     G1RegionMarkStats _stats;
  71 
  72     void clear() {
  73       _region_idx = 0;
  74       _stats.clear();
  75     }
  76 
  77     bool is_clear() const {
  78       return _region_idx == 0 && _stats.is_clear();
  79     }
  80   };
  81 
  82   // The actual cache and its number of entries.
  83   G1RegionMarkStatsCacheEntry* _cache;
  84   uint _num_cache_entries;
  85 
  86   // Cache hits/miss counters.
  87   size_t _cache_hits;
  88   size_t _cache_misses;
  89 
  90   // Evict a given element of the statistics cache.
  91   void evict(uint idx);
  92 
  93   size_t _num_cache_entries_mask;
  94 
  95   uint hash(uint idx) {
  96     return idx & _num_cache_entries_mask;
  97   }
  98 
  99   G1RegionMarkStatsCacheEntry* find_for_add(uint region_idx);
 100 public:
 101   G1RegionMarkStatsCache(G1RegionMarkStats* target, uint num_cache_entries);
 102 
 103   ~G1RegionMarkStatsCache();
 104 
 105   void add_live_words(uint region_idx, size_t live_words) {
 106     G1RegionMarkStatsCacheEntry* const cur = find_for_add(region_idx);
 107     cur->_stats._live_words += live_words;
 108   }
 109 
 110   void reset(uint region_idx) {
 111     uint const cache_idx = hash(region_idx);
 112     G1RegionMarkStatsCacheEntry* cur = &_cache[cache_idx];
 113     if (cur->_region_idx == region_idx) {
 114       _cache[cache_idx].clear();
 115     }
 116   }
 117 
 118   // Evict all remaining statistics, returning cache hits and misses.
 119   Pair<size_t, size_t> evict_all();
 120 
 121   // Reset all cache entries to their default values.
 122   void reset();
 123 
 124   size_t hits() const { return _cache_hits; }
 125   size_t misses() const { return _cache_misses; }
 126 };
 127 
 128 #endif // SHARE_GC_G1_G1REGIONMARKSTATSCACHE_HPP