8038930: G1CodeRootSet::test fails with assert(_num_chunks_handed_out == 0) failed: No elements must have been handed out yet

Wed, 16 Apr 2014 10:14:50 +0200

author
tschatzl
date
Wed, 16 Apr 2014 10:14:50 +0200
changeset 6925
82693fb204a5
parent 6924
3a62cd59c8d8
child 6926
d7e2d5f2846b

8038930: G1CodeRootSet::test fails with assert(_num_chunks_handed_out == 0) failed: No elements must have been handed out yet
Summary: The test incorrectly assumed that it had been started with no other previous compilation activity. Fix this by allowing multiple code root free chunk lists, and use one separate from the global one to perform the test.
Reviewed-by: brutisso

src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp	Tue May 20 10:04:03 2014 -0700
     1.2 +++ b/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp	Wed Apr 16 10:14:50 2014 +0200
     1.3 @@ -47,32 +47,27 @@
     1.4    }
     1.5  }
     1.6  
     1.7 -FreeList<G1CodeRootChunk> G1CodeRootSet::_free_list;
     1.8 -size_t G1CodeRootSet::_num_chunks_handed_out = 0;
     1.9 -
    1.10 -G1CodeRootChunk* G1CodeRootSet::new_chunk() {
    1.11 -  G1CodeRootChunk* result = _free_list.get_chunk_at_head();
    1.12 -  if (result == NULL) {
    1.13 -    result = new G1CodeRootChunk();
    1.14 -  }
    1.15 -  G1CodeRootSet::_num_chunks_handed_out++;
    1.16 -  result->reset();
    1.17 -  return result;
    1.18 +G1CodeRootChunkManager::G1CodeRootChunkManager() : _free_list(), _num_chunks_handed_out(0) {
    1.19 +  _free_list.initialize();
    1.20 +  _free_list.set_size(G1CodeRootChunk::word_size());
    1.21  }
    1.22  
    1.23 -void G1CodeRootSet::free_chunk(G1CodeRootChunk* chunk) {
    1.24 -  _free_list.return_chunk_at_head(chunk);
    1.25 -  G1CodeRootSet::_num_chunks_handed_out--;
    1.26 +size_t G1CodeRootChunkManager::fl_mem_size() {
    1.27 +  return _free_list.count() * _free_list.size();
    1.28  }
    1.29  
    1.30 -void G1CodeRootSet::free_all_chunks(FreeList<G1CodeRootChunk>* list) {
    1.31 -  G1CodeRootSet::_num_chunks_handed_out -= list->count();
    1.32 +void G1CodeRootChunkManager::free_all_chunks(FreeList<G1CodeRootChunk>* list) {
    1.33 +  _num_chunks_handed_out -= list->count();
    1.34    _free_list.prepend(list);
    1.35  }
    1.36  
    1.37 -void G1CodeRootSet::purge_chunks(size_t keep_ratio) {
    1.38 -  size_t keep = G1CodeRootSet::_num_chunks_handed_out * keep_ratio / 100;
    1.39 +void G1CodeRootChunkManager::free_chunk(G1CodeRootChunk* chunk) {
    1.40 +  _free_list.return_chunk_at_head(chunk);
    1.41 +  _num_chunks_handed_out--;
    1.42 +}
    1.43  
    1.44 +void G1CodeRootChunkManager::purge_chunks(size_t keep_ratio) {
    1.45 +  size_t keep = _num_chunks_handed_out * keep_ratio / 100;
    1.46    if (keep >= (size_t)_free_list.count()) {
    1.47      return;
    1.48    }
    1.49 @@ -90,20 +85,51 @@
    1.50    }
    1.51  }
    1.52  
    1.53 -size_t G1CodeRootSet::static_mem_size() {
    1.54 -  return sizeof(_free_list) + sizeof(_num_chunks_handed_out);
    1.55 +size_t G1CodeRootChunkManager::static_mem_size() {
    1.56 +  return sizeof(this);
    1.57  }
    1.58  
    1.59 -size_t G1CodeRootSet::fl_mem_size() {
    1.60 -  return _free_list.count() * _free_list.size();
    1.61 +
    1.62 +G1CodeRootChunk* G1CodeRootChunkManager::new_chunk() {
    1.63 +  G1CodeRootChunk* result = _free_list.get_chunk_at_head();
    1.64 +  if (result == NULL) {
    1.65 +    result = new G1CodeRootChunk();
    1.66 +  }
    1.67 +  _num_chunks_handed_out++;
    1.68 +  result->reset();
    1.69 +  return result;
    1.70  }
    1.71  
    1.72 -void G1CodeRootSet::initialize() {
    1.73 -  _free_list.initialize();
    1.74 -  _free_list.set_size(G1CodeRootChunk::word_size());
    1.75 +#ifndef PRODUCT
    1.76 +
    1.77 +size_t G1CodeRootChunkManager::num_chunks_handed_out() const {
    1.78 +  return _num_chunks_handed_out;
    1.79  }
    1.80  
    1.81 -G1CodeRootSet::G1CodeRootSet() : _list(), _length(0) {
    1.82 +size_t G1CodeRootChunkManager::num_free_chunks() const {
    1.83 +  return (size_t)_free_list.count();
    1.84 +}
    1.85 +
    1.86 +#endif
    1.87 +
    1.88 +G1CodeRootChunkManager G1CodeRootSet::_default_chunk_manager;
    1.89 +
    1.90 +void G1CodeRootSet::purge_chunks(size_t keep_ratio) {
    1.91 +  _default_chunk_manager.purge_chunks(keep_ratio);
    1.92 +}
    1.93 +
    1.94 +size_t G1CodeRootSet::static_mem_size() {
    1.95 +  return _default_chunk_manager.static_mem_size();
    1.96 +}
    1.97 +
    1.98 +size_t G1CodeRootSet::free_chunks_mem_size() {
    1.99 +  return _default_chunk_manager.fl_mem_size();
   1.100 +}
   1.101 +
   1.102 +G1CodeRootSet::G1CodeRootSet(G1CodeRootChunkManager* manager) : _manager(manager), _list(), _length(0) {
   1.103 +  if (_manager == NULL) {
   1.104 +    _manager = &_default_chunk_manager;
   1.105 +  }
   1.106    _list.initialize();
   1.107    _list.set_size(G1CodeRootChunk::word_size());
   1.108  }
   1.109 @@ -196,21 +222,21 @@
   1.110  #ifndef PRODUCT
   1.111  
   1.112  void G1CodeRootSet::test() {
   1.113 -  initialize();
   1.114 +  G1CodeRootChunkManager mgr;
   1.115  
   1.116 -  assert(_free_list.count() == 0, "Free List must be empty");
   1.117 -  assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet");
   1.118 +  assert(mgr.num_chunks_handed_out() == 0, "Must not have handed out chunks yet");
   1.119  
   1.120    // The number of chunks that we allocate for purge testing.
   1.121    size_t const num_chunks = 10;
   1.122 +
   1.123    {
   1.124 -    G1CodeRootSet set1;
   1.125 +    G1CodeRootSet set1(&mgr);
   1.126      assert(set1.is_empty(), "Code root set must be initially empty but is not.");
   1.127  
   1.128      set1.add((nmethod*)1);
   1.129 -    assert(_num_chunks_handed_out == 1,
   1.130 +    assert(mgr.num_chunks_handed_out() == 1,
   1.131             err_msg("Must have allocated and handed out one chunk, but handed out "
   1.132 -                   SIZE_FORMAT" chunks", _num_chunks_handed_out));
   1.133 +                   SIZE_FORMAT" chunks", mgr.num_chunks_handed_out()));
   1.134      assert(set1.length() == 1, err_msg("Added exactly one element, but set contains "
   1.135                                         SIZE_FORMAT" elements", set1.length()));
   1.136  
   1.137 @@ -219,19 +245,19 @@
   1.138      for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) {
   1.139        set1.add((nmethod*)1);
   1.140      }
   1.141 -    assert(_num_chunks_handed_out == 1,
   1.142 +    assert(mgr.num_chunks_handed_out() == 1,
   1.143             err_msg("Duplicate detection must have prevented allocation of further "
   1.144 -                   "chunks but contains "SIZE_FORMAT, _num_chunks_handed_out));
   1.145 +                   "chunks but allocated "SIZE_FORMAT, mgr.num_chunks_handed_out()));
   1.146      assert(set1.length() == 1,
   1.147             err_msg("Duplicate detection should not have increased the set size but "
   1.148                     "is "SIZE_FORMAT, set1.length()));
   1.149  
   1.150      size_t num_total_after_add = G1CodeRootChunk::word_size() + 1;
   1.151      for (size_t i = 0; i < num_total_after_add - 1; i++) {
   1.152 -      set1.add((nmethod*)(2 + i));
   1.153 +      set1.add((nmethod*)(uintptr_t)(2 + i));
   1.154      }
   1.155 -    assert(_num_chunks_handed_out > 1,
   1.156 -           "After adding more code roots, more than one chunks should have been handed out");
   1.157 +    assert(mgr.num_chunks_handed_out() > 1,
   1.158 +           "After adding more code roots, more than one additional chunk should have been handed out");
   1.159      assert(set1.length() == num_total_after_add,
   1.160             err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they "
   1.161                     "need to be in the set, but there are only "SIZE_FORMAT,
   1.162 @@ -244,27 +270,27 @@
   1.163      assert(num_popped == num_total_after_add,
   1.164             err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" "
   1.165                     "were added", num_popped, num_total_after_add));
   1.166 -    assert(_num_chunks_handed_out == 0,
   1.167 +    assert(mgr.num_chunks_handed_out() == 0,
   1.168             err_msg("After popping all elements, all chunks must have been returned "
   1.169 -                   "but are still "SIZE_FORMAT, _num_chunks_handed_out));
   1.170 +                   "but there are still "SIZE_FORMAT" additional", mgr.num_chunks_handed_out()));
   1.171  
   1.172 -    purge_chunks(0);
   1.173 -    assert(_free_list.count() == 0,
   1.174 +    mgr.purge_chunks(0);
   1.175 +    assert(mgr.num_free_chunks() == 0,
   1.176             err_msg("After purging everything, the free list must be empty but still "
   1.177 -                   "contains "SIZE_FORMAT" chunks", _free_list.count()));
   1.178 +                   "contains "SIZE_FORMAT" chunks", mgr.num_free_chunks()));
   1.179  
   1.180      // Add some more handed out chunks.
   1.181      size_t i = 0;
   1.182 -    while (_num_chunks_handed_out < num_chunks) {
   1.183 +    while (mgr.num_chunks_handed_out() < num_chunks) {
   1.184        set1.add((nmethod*)i);
   1.185        i++;
   1.186      }
   1.187  
   1.188      {
   1.189        // Generate chunks on the free list.
   1.190 -      G1CodeRootSet set2;
   1.191 +      G1CodeRootSet set2(&mgr);
   1.192        size_t i = 0;
   1.193 -      while (_num_chunks_handed_out < num_chunks * 2) {
   1.194 +      while (mgr.num_chunks_handed_out() < (num_chunks * 2)) {
   1.195          set2.add((nmethod*)i);
   1.196          i++;
   1.197        }
   1.198 @@ -272,45 +298,45 @@
   1.199        // num_chunks elements on the free list.
   1.200      }
   1.201  
   1.202 -    assert(_num_chunks_handed_out == num_chunks,
   1.203 +    assert(mgr.num_chunks_handed_out() == num_chunks,
   1.204             err_msg("Deletion of the second set must have resulted in giving back "
   1.205 -                   "those, but there is still "SIZE_FORMAT" handed out, expecting "
   1.206 -                   SIZE_FORMAT, _num_chunks_handed_out, num_chunks));
   1.207 -    assert((size_t)_free_list.count() == num_chunks,
   1.208 +                   "those, but there are still "SIZE_FORMAT" additional handed out, expecting "
   1.209 +                   SIZE_FORMAT, mgr.num_chunks_handed_out(), num_chunks));
   1.210 +    assert(mgr.num_free_chunks() == num_chunks,
   1.211             err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
   1.212 -                   "but there are only "SIZE_FORMAT, num_chunks, _free_list.count()));
   1.213 +                   "but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks()));
   1.214  
   1.215      size_t const test_percentage = 50;
   1.216 -    purge_chunks(test_percentage);
   1.217 -    assert(_num_chunks_handed_out == num_chunks,
   1.218 +    mgr.purge_chunks(test_percentage);
   1.219 +    assert(mgr.num_chunks_handed_out() == num_chunks,
   1.220             err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT,
   1.221 -                   _num_chunks_handed_out));
   1.222 -    assert((size_t)_free_list.count() == (ssize_t)(num_chunks * test_percentage / 100),
   1.223 +                   mgr.num_chunks_handed_out()));
   1.224 +    assert(mgr.num_free_chunks() == (size_t)(mgr.num_chunks_handed_out() * test_percentage / 100),
   1.225             err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks"
   1.226 -                   "but there are "SSIZE_FORMAT, test_percentage, num_chunks,
   1.227 -                   _free_list.count()));
   1.228 +                   "but there are "SIZE_FORMAT, test_percentage, num_chunks,
   1.229 +                   mgr.num_free_chunks()));
   1.230      // Purge the remainder of the chunks on the free list.
   1.231 -    purge_chunks(0);
   1.232 -    assert(_free_list.count() == 0, "Free List must be empty");
   1.233 -    assert(_num_chunks_handed_out == num_chunks,
   1.234 +    mgr.purge_chunks(0);
   1.235 +    assert(mgr.num_free_chunks() == 0, "Free List must be empty");
   1.236 +    assert(mgr.num_chunks_handed_out() == num_chunks,
   1.237             err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set "
   1.238 -                   "but there are "SIZE_FORMAT, num_chunks, _num_chunks_handed_out));
   1.239 +                   "but there are "SIZE_FORMAT, num_chunks, mgr.num_chunks_handed_out()));
   1.240  
   1.241      // Exit of the scope of the set1 object will call the destructor that generates
   1.242      // num_chunks additional elements on the free list.
   1.243 -  }
   1.244 +   }
   1.245  
   1.246 -  assert(_num_chunks_handed_out == 0,
   1.247 +  assert(mgr.num_chunks_handed_out() == 0,
   1.248           err_msg("Deletion of the only set must have resulted in no chunks handed "
   1.249 -                 "out, but there is still "SIZE_FORMAT" handed out", _num_chunks_handed_out));
   1.250 -  assert((size_t)_free_list.count() == num_chunks,
   1.251 +                 "out, but there is still "SIZE_FORMAT" handed out", mgr.num_chunks_handed_out()));
   1.252 +  assert(mgr.num_free_chunks() == num_chunks,
   1.253           err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
   1.254 -                 "but there are only "SSIZE_FORMAT, num_chunks, _free_list.count()));
   1.255 +                 "but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks()));
   1.256  
   1.257    // Restore initial state.
   1.258 -  purge_chunks(0);
   1.259 -  assert(_free_list.count() == 0, "Free List must be empty");
   1.260 -  assert(_num_chunks_handed_out == 0, "No elements must have been handed out yet");
   1.261 +  mgr.purge_chunks(0);
   1.262 +  assert(mgr.num_free_chunks() == 0, "Free List must be empty");
   1.263 +  assert(mgr.num_chunks_handed_out() == 0, "No additional elements must have been handed out yet");
   1.264  }
   1.265  
   1.266  void TestCodeCacheRemSet_test() {
     2.1 --- a/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp	Tue May 20 10:04:03 2014 -0700
     2.2 +++ b/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.hpp	Wed Apr 16 10:14:50 2014 +0200
     2.3 @@ -128,19 +128,45 @@
     2.4    }
     2.5  };
     2.6  
     2.7 +// Manages free chunks.
     2.8 +class G1CodeRootChunkManager VALUE_OBJ_CLASS_SPEC {
     2.9 + private:
    2.10 +  // Global free chunk list management
    2.11 +  FreeList<G1CodeRootChunk> _free_list;
    2.12 +  // Total number of chunks handed out
    2.13 +  size_t _num_chunks_handed_out;
    2.14 +
    2.15 + public:
    2.16 +  G1CodeRootChunkManager();
    2.17 +
    2.18 +  G1CodeRootChunk* new_chunk();
    2.19 +  void free_chunk(G1CodeRootChunk* chunk);
    2.20 +  // Free all elements of the given list.
    2.21 +  void free_all_chunks(FreeList<G1CodeRootChunk>* list);
    2.22 +
    2.23 +  void initialize();
    2.24 +  void purge_chunks(size_t keep_ratio);
    2.25 +
    2.26 +  size_t static_mem_size();
    2.27 +  size_t fl_mem_size();
    2.28 +
    2.29 +#ifndef PRODUCT
    2.30 +  size_t num_chunks_handed_out() const;
    2.31 +  size_t num_free_chunks() const;
    2.32 +#endif
    2.33 +};
    2.34 +
    2.35  // Implements storage for a set of code roots.
    2.36  // All methods that modify the set are not thread-safe except if otherwise noted.
    2.37  class G1CodeRootSet VALUE_OBJ_CLASS_SPEC {
    2.38   private:
    2.39 -  // Global free chunk list management
    2.40 -  static FreeList<G1CodeRootChunk> _free_list;
    2.41 -  // Total number of chunks handed out
    2.42 -  static size_t _num_chunks_handed_out;
    2.43 +  // Global default free chunk manager instance.
    2.44 +  static G1CodeRootChunkManager _default_chunk_manager;
    2.45  
    2.46 -  static G1CodeRootChunk* new_chunk();
    2.47 -  static void free_chunk(G1CodeRootChunk* chunk);
    2.48 +  G1CodeRootChunk* new_chunk() { return _manager->new_chunk(); }
    2.49 +  void free_chunk(G1CodeRootChunk* chunk) { _manager->free_chunk(chunk); }
    2.50    // Free all elements of the given list.
    2.51 -  static void free_all_chunks(FreeList<G1CodeRootChunk>* list);
    2.52 +  void free_all_chunks(FreeList<G1CodeRootChunk>* list) { _manager->free_all_chunks(list); }
    2.53  
    2.54    // Return the chunk that contains the given nmethod, NULL otherwise.
    2.55    // Scans the list of chunks backwards, as this method is used to add new
    2.56 @@ -150,16 +176,18 @@
    2.57  
    2.58    size_t _length;
    2.59    FreeList<G1CodeRootChunk> _list;
    2.60 +  G1CodeRootChunkManager* _manager;
    2.61  
    2.62   public:
    2.63 -  G1CodeRootSet();
    2.64 +  // If an instance is initialized with a chunk manager of NULL, use the global
    2.65 +  // default one.
    2.66 +  G1CodeRootSet(G1CodeRootChunkManager* manager = NULL);
    2.67    ~G1CodeRootSet();
    2.68  
    2.69 -  static void initialize();
    2.70    static void purge_chunks(size_t keep_ratio);
    2.71  
    2.72    static size_t static_mem_size();
    2.73 -  static size_t fl_mem_size();
    2.74 +  static size_t free_chunks_mem_size();
    2.75  
    2.76    // Search for the code blob from the recently allocated ones to find duplicates more quickly, as this
    2.77    // method is likely to be repeatedly called with the same nmethod.
     3.1 --- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Tue May 20 10:04:03 2014 -0700
     3.2 +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Wed Apr 16 10:14:50 2014 +0200
     3.3 @@ -355,7 +355,7 @@
     3.4    // Returns the memory occupancy of all free_list data structures associated
     3.5    // with remembered sets.
     3.6    static size_t fl_mem_size() {
     3.7 -    return OtherRegionsTable::fl_mem_size() + G1CodeRootSet::fl_mem_size();
     3.8 +    return OtherRegionsTable::fl_mem_size() + G1CodeRootSet::free_chunks_mem_size();
     3.9    }
    3.10  
    3.11    bool contains_reference(OopOrNarrowOopStar from) const {
    3.12 @@ -400,7 +400,6 @@
    3.13    // Declare the heap size (in # of regions) to the HeapRegionRemSet(s).
    3.14    // (Uses it to initialize from_card_cache).
    3.15    static void init_heap(uint max_regions) {
    3.16 -    G1CodeRootSet::initialize();
    3.17      OtherRegionsTable::init_from_card_cache(max_regions);
    3.18    }
    3.19  

mercurial