Mercurial > hg > graal-jvmci-8
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()), |