comparison src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @ 17753:191174b49bec

8035406: Improve data structure for Code Cache remembered sets Summary: Change the code cache remembered sets data structure from a GrowableArray to a chunked list of nmethods. This makes the data structure more amenable to parallelization, and decreases freeing time. Reviewed-by: mgerdin, brutisso
author tschatzl
date Mon, 24 Mar 2014 15:30:14 +0100
parents 28674af341ac
children d7070f371770
comparison
equal deleted inserted replaced
17750:f53edbc2b728 17753:191174b49bec
1 /* 1 /*
2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 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 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
257 size_t OtherRegionsTable::_max_fine_entries = 0; 257 size_t OtherRegionsTable::_max_fine_entries = 0;
258 size_t OtherRegionsTable::_mod_max_fine_entries_mask = 0; 258 size_t OtherRegionsTable::_mod_max_fine_entries_mask = 0;
259 size_t OtherRegionsTable::_fine_eviction_stride = 0; 259 size_t OtherRegionsTable::_fine_eviction_stride = 0;
260 size_t OtherRegionsTable::_fine_eviction_sample_size = 0; 260 size_t OtherRegionsTable::_fine_eviction_sample_size = 0;
261 261
262 OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) : 262 OtherRegionsTable::OtherRegionsTable(HeapRegion* hr, Mutex* m) :
263 _g1h(G1CollectedHeap::heap()), 263 _g1h(G1CollectedHeap::heap()),
264 _m(Mutex::leaf, "An OtherRegionsTable lock", true), 264 _hr(hr), _m(m),
265 _hr(hr),
266 _coarse_map(G1CollectedHeap::heap()->max_regions(), 265 _coarse_map(G1CollectedHeap::heap()->max_regions(),
267 false /* in-resource-area */), 266 false /* in-resource-area */),
268 _fine_grain_regions(NULL), 267 _fine_grain_regions(NULL),
269 _first_all_fine_prts(NULL), _last_all_fine_prts(NULL), 268 _first_all_fine_prts(NULL), _last_all_fine_prts(NULL),
270 _n_fine_entries(0), _n_coarse_entries(0), 269 _n_fine_entries(0), _n_coarse_entries(0),
440 439
441 // Otherwise find a per-region table to add it to. 440 // Otherwise find a per-region table to add it to.
442 size_t ind = from_hrs_ind & _mod_max_fine_entries_mask; 441 size_t ind = from_hrs_ind & _mod_max_fine_entries_mask;
443 PerRegionTable* prt = find_region_table(ind, from_hr); 442 PerRegionTable* prt = find_region_table(ind, from_hr);
444 if (prt == NULL) { 443 if (prt == NULL) {
445 MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); 444 MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
446 // Confirm that it's really not there... 445 // Confirm that it's really not there...
447 prt = find_region_table(ind, from_hr); 446 prt = find_region_table(ind, from_hr);
448 if (prt == NULL) { 447 if (prt == NULL) {
449 448
450 uintptr_t from_hr_bot_card_index = 449 uintptr_t from_hr_bot_card_index =
542 } 541 }
543 542
544 jint OtherRegionsTable::_n_coarsenings = 0; 543 jint OtherRegionsTable::_n_coarsenings = 0;
545 544
546 PerRegionTable* OtherRegionsTable::delete_region_table() { 545 PerRegionTable* OtherRegionsTable::delete_region_table() {
547 assert(_m.owned_by_self(), "Precondition"); 546 assert(_m->owned_by_self(), "Precondition");
548 assert(_n_fine_entries == _max_fine_entries, "Precondition"); 547 assert(_n_fine_entries == _max_fine_entries, "Precondition");
549 PerRegionTable* max = NULL; 548 PerRegionTable* max = NULL;
550 jint max_occ = 0; 549 jint max_occ = 0;
551 PerRegionTable** max_prev; 550 PerRegionTable** max_prev;
552 size_t max_ind; 551 size_t max_ind;
674 clear_fcc(); 673 clear_fcc();
675 } 674 }
676 675
677 676
678 size_t OtherRegionsTable::occupied() const { 677 size_t OtherRegionsTable::occupied() const {
679 // Cast away const in this case.
680 MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
681 size_t sum = occ_fine(); 678 size_t sum = occ_fine();
682 sum += occ_sparse(); 679 sum += occ_sparse();
683 sum += occ_coarse(); 680 sum += occ_coarse();
684 return sum; 681 return sum;
685 } 682 }
705 size_t OtherRegionsTable::occ_sparse() const { 702 size_t OtherRegionsTable::occ_sparse() const {
706 return _sparse_table.occupied(); 703 return _sparse_table.occupied();
707 } 704 }
708 705
709 size_t OtherRegionsTable::mem_size() const { 706 size_t OtherRegionsTable::mem_size() const {
710 // Cast away const in this case.
711 MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
712 size_t sum = 0; 707 size_t sum = 0;
713 // all PRTs are of the same size so it is sufficient to query only one of them. 708 // all PRTs are of the same size so it is sufficient to query only one of them.
714 if (_first_all_fine_prts != NULL) { 709 if (_first_all_fine_prts != NULL) {
715 assert(_last_all_fine_prts != NULL && 710 assert(_last_all_fine_prts != NULL &&
716 _first_all_fine_prts->mem_size() == _last_all_fine_prts->mem_size(), "check that mem_size() is constant"); 711 _first_all_fine_prts->mem_size() == _last_all_fine_prts->mem_size(), "check that mem_size() is constant");
737 _from_card_cache[i][hrs_idx] = -1; 732 _from_card_cache[i][hrs_idx] = -1;
738 } 733 }
739 } 734 }
740 735
741 void OtherRegionsTable::clear() { 736 void OtherRegionsTable::clear() {
742 MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
743 // if there are no entries, skip this step 737 // if there are no entries, skip this step
744 if (_first_all_fine_prts != NULL) { 738 if (_first_all_fine_prts != NULL) {
745 guarantee(_first_all_fine_prts != NULL && _last_all_fine_prts != NULL, "just checking"); 739 guarantee(_first_all_fine_prts != NULL && _last_all_fine_prts != NULL, "just checking");
746 PerRegionTable::bulk_free(_first_all_fine_prts, _last_all_fine_prts); 740 PerRegionTable::bulk_free(_first_all_fine_prts, _last_all_fine_prts);
747 memset(_fine_grain_regions, 0, _max_fine_entries * sizeof(_fine_grain_regions[0])); 741 memset(_fine_grain_regions, 0, _max_fine_entries * sizeof(_fine_grain_regions[0]));
757 751
758 clear_fcc(); 752 clear_fcc();
759 } 753 }
760 754
761 void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) { 755 void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) {
762 MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); 756 MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
763 size_t hrs_ind = (size_t) from_hr->hrs_index(); 757 size_t hrs_ind = (size_t) from_hr->hrs_index();
764 size_t ind = hrs_ind & _mod_max_fine_entries_mask; 758 size_t ind = hrs_ind & _mod_max_fine_entries_mask;
765 if (del_single_region_table(ind, from_hr)) { 759 if (del_single_region_table(ind, from_hr)) {
766 assert(!_coarse_map.at(hrs_ind), "Inv"); 760 assert(!_coarse_map.at(hrs_ind), "Inv");
767 } else { 761 } else {
803 } 797 }
804 } 798 }
805 799
806 bool OtherRegionsTable::contains_reference(OopOrNarrowOopStar from) const { 800 bool OtherRegionsTable::contains_reference(OopOrNarrowOopStar from) const {
807 // Cast away const in this case. 801 // Cast away const in this case.
808 MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag); 802 MutexLockerEx x((Mutex*)_m, Mutex::_no_safepoint_check_flag);
809 return contains_reference_locked(from); 803 return contains_reference_locked(from);
810 } 804 }
811 805
812 bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const { 806 bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const {
813 HeapRegion* hr = _g1h->heap_region_containing_raw(from); 807 HeapRegion* hr = _g1h->heap_region_containing_raw(from);
848 return (int)MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads); 842 return (int)MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads);
849 } 843 }
850 844
851 HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, 845 HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
852 HeapRegion* hr) 846 HeapRegion* hr)
853 : _bosa(bosa), _strong_code_roots_list(NULL), _other_regions(hr) { 847 : _bosa(bosa),
848 _m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #"UINT32_FORMAT, hr->hrs_index()), true),
849 _code_roots(), _other_regions(hr, &_m) {
854 reset_for_par_iteration(); 850 reset_for_par_iteration();
855 } 851 }
856 852
857 void HeapRegionRemSet::setup_remset_size() { 853 void HeapRegionRemSet::setup_remset_size() {
858 // Setup sparse and fine-grain tables sizes. 854 // Setup sparse and fine-grain tables sizes.
881 bool HeapRegionRemSet::iter_is_complete() { 877 bool HeapRegionRemSet::iter_is_complete() {
882 return _iter_state == Complete; 878 return _iter_state == Complete;
883 } 879 }
884 880
885 #ifndef PRODUCT 881 #ifndef PRODUCT
886 void HeapRegionRemSet::print() const { 882 void HeapRegionRemSet::print() {
887 HeapRegionRemSetIterator iter(this); 883 HeapRegionRemSetIterator iter(this);
888 size_t card_index; 884 size_t card_index;
889 while (iter.has_next(card_index)) { 885 while (iter.has_next(card_index)) {
890 HeapWord* card_start = 886 HeapWord* card_start =
891 G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index); 887 G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index);
907 void HeapRegionRemSet::cleanup() { 903 void HeapRegionRemSet::cleanup() {
908 SparsePRT::cleanup_all(); 904 SparsePRT::cleanup_all();
909 } 905 }
910 906
911 void HeapRegionRemSet::clear() { 907 void HeapRegionRemSet::clear() {
912 if (_strong_code_roots_list != NULL) { 908 MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
913 delete _strong_code_roots_list; 909 clear_locked();
914 } 910 }
915 _strong_code_roots_list = new (ResourceObj::C_HEAP, mtGC) 911
916 GrowableArray<nmethod*>(10, 0, NULL, true); 912 void HeapRegionRemSet::clear_locked() {
917 913 _code_roots.clear();
918 _other_regions.clear(); 914 _other_regions.clear();
919 assert(occupied() == 0, "Should be clear."); 915 assert(occupied_locked() == 0, "Should be clear.");
920 reset_for_par_iteration(); 916 reset_for_par_iteration();
921 } 917 }
922 918
923 void HeapRegionRemSet::reset_for_par_iteration() { 919 void HeapRegionRemSet::reset_for_par_iteration() {
924 _iter_state = Unclaimed; 920 _iter_state = Unclaimed;
935 931
936 // Code roots support 932 // Code roots support
937 933
938 void HeapRegionRemSet::add_strong_code_root(nmethod* nm) { 934 void HeapRegionRemSet::add_strong_code_root(nmethod* nm) {
939 assert(nm != NULL, "sanity"); 935 assert(nm != NULL, "sanity");
940 // Search for the code blob from the RHS to avoid 936 _code_roots.add(nm);
941 // duplicate entries as much as possible
942 if (_strong_code_roots_list->find_from_end(nm) < 0) {
943 // Code blob isn't already in the list
944 _strong_code_roots_list->push(nm);
945 }
946 } 937 }
947 938
948 void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) { 939 void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) {
949 assert(nm != NULL, "sanity"); 940 assert(nm != NULL, "sanity");
950 int idx = _strong_code_roots_list->find(nm); 941 _code_roots.remove(nm);
951 if (idx >= 0) {
952 _strong_code_roots_list->remove_at(idx);
953 }
954 // Check that there were no duplicates 942 // Check that there were no duplicates
955 guarantee(_strong_code_roots_list->find(nm) < 0, "duplicate entry found"); 943 guarantee(!_code_roots.contains(nm), "duplicate entry found");
956 } 944 }
957 945
958 class NMethodMigrationOopClosure : public OopClosure { 946 class NMethodMigrationOopClosure : public OopClosure {
959 G1CollectedHeap* _g1h; 947 G1CollectedHeap* _g1h;
960 HeapRegion* _from; 948 HeapRegion* _from;
1012 1000
1013 // List of code blobs to retain for this region 1001 // List of code blobs to retain for this region
1014 GrowableArray<nmethod*> to_be_retained(10); 1002 GrowableArray<nmethod*> to_be_retained(10);
1015 G1CollectedHeap* g1h = G1CollectedHeap::heap(); 1003 G1CollectedHeap* g1h = G1CollectedHeap::heap();
1016 1004
1017 while (_strong_code_roots_list->is_nonempty()) { 1005 while (!_code_roots.is_empty()) {
1018 nmethod *nm = _strong_code_roots_list->pop(); 1006 nmethod *nm = _code_roots.pop();
1019 if (nm != NULL) { 1007 if (nm != NULL) {
1020 NMethodMigrationOopClosure oop_cl(g1h, hr(), nm); 1008 NMethodMigrationOopClosure oop_cl(g1h, hr(), nm);
1021 nm->oops_do(&oop_cl); 1009 nm->oops_do(&oop_cl);
1022 if (oop_cl.retain()) { 1010 if (oop_cl.retain()) {
1023 to_be_retained.push(nm); 1011 to_be_retained.push(nm);
1036 add_strong_code_root(nm); 1024 add_strong_code_root(nm);
1037 } 1025 }
1038 } 1026 }
1039 1027
1040 void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const { 1028 void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const {
1041 for (int i = 0; i < _strong_code_roots_list->length(); i += 1) { 1029 _code_roots.nmethods_do(blk);
1042 nmethod* nm = _strong_code_roots_list->at(i);
1043 blk->do_code_blob(nm);
1044 }
1045 } 1030 }
1046 1031
1047 size_t HeapRegionRemSet::strong_code_roots_mem_size() { 1032 size_t HeapRegionRemSet::strong_code_roots_mem_size() {
1048 return sizeof(GrowableArray<nmethod*>) + 1033 return _code_roots.mem_size();
1049 _strong_code_roots_list->max_length() * sizeof(nmethod*);
1050 } 1034 }
1051 1035
1052 //-------------------- Iteration -------------------- 1036 //-------------------- Iteration --------------------
1053 1037
1054 HeapRegionRemSetIterator:: HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs) : 1038 HeapRegionRemSetIterator:: HeapRegionRemSetIterator(HeapRegionRemSet* hrrs) :
1055 _hrrs(hrrs), 1039 _hrrs(hrrs),
1056 _g1h(G1CollectedHeap::heap()), 1040 _g1h(G1CollectedHeap::heap()),
1057 _coarse_map(&hrrs->_other_regions._coarse_map), 1041 _coarse_map(&hrrs->_other_regions._coarse_map),
1058 _fine_grain_regions(hrrs->_other_regions._fine_grain_regions), 1042 _fine_grain_regions(hrrs->_other_regions._fine_grain_regions),
1059 _bosa(hrrs->bosa()), 1043 _bosa(hrrs->bosa()),