comparison src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp @ 1145:e018e6884bd8

6631166: CMS: better heuristics when combatting fragmentation Summary: Autonomic per-worker free block cache sizing, tunable coalition policies, fixes to per-size block statistics, retuned gain and bandwidth of some feedback loop filters to allow quicker reactivity to abrupt changes in ambient demand, and other heuristics to reduce fragmentation of the CMS old gen. Also tightened some assertions, including those related to locking. Reviewed-by: jmasa
author ysr
date Wed, 23 Dec 2009 09:23:54 -0800
parents 850fdf70db2b
children cff162798819
comparison
equal deleted inserted replaced
1111:44f61c24ddab 1145:e018e6884bd8
60 tl->set_hint(0); 60 tl->set_hint(0);
61 tl->set_size(tc->size()); 61 tl->set_size(tc->size());
62 tl->link_head(tc); 62 tl->link_head(tc);
63 tl->link_tail(tc); 63 tl->link_tail(tc);
64 tl->set_count(1); 64 tl->set_count(1);
65 tl->init_statistics(); 65 tl->init_statistics(true /* split_birth */);
66 tl->setParent(NULL); 66 tl->setParent(NULL);
67 tl->setLeft(NULL); 67 tl->setLeft(NULL);
68 tl->setRight(NULL); 68 tl->setRight(NULL);
69 return tl; 69 return tl;
70 } 70 }
71
71 TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) { 72 TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) {
72 TreeChunk* tc = (TreeChunk*) addr; 73 TreeChunk* tc = (TreeChunk*) addr;
73 assert(size >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk"); 74 assert(size >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk");
74 // The space in the heap will have been mangled initially but 75 // The space in the heap will have been mangled initially but
75 // is not remangled when a free chunk is returned to the free list 76 // is not remangled when a free chunk is returned to the free list
265 } 266 }
266 assert(retTC->list() == this, "Wrong type of chunk."); 267 assert(retTC->list() == this, "Wrong type of chunk.");
267 return retTC; 268 return retTC;
268 } 269 }
269 270
271 // Returns the block with the largest heap address amongst
272 // those in the list for this size; potentially slow and expensive,
273 // use with caution!
274 TreeChunk* TreeList::largest_address() {
275 guarantee(head() != NULL, "The head of the list cannot be NULL");
276 FreeChunk* fc = head()->next();
277 TreeChunk* retTC;
278 if (fc == NULL) {
279 retTC = head_as_TreeChunk();
280 } else {
281 // walk down the list and return the one with the highest
282 // heap address among chunks of this size.
283 FreeChunk* last = fc;
284 while (fc->next() != NULL) {
285 if ((HeapWord*)last < (HeapWord*)fc) {
286 last = fc;
287 }
288 fc = fc->next();
289 }
290 retTC = TreeChunk::as_TreeChunk(last);
291 }
292 assert(retTC->list() == this, "Wrong type of chunk.");
293 return retTC;
294 }
295
270 BinaryTreeDictionary::BinaryTreeDictionary(MemRegion mr, bool splay): 296 BinaryTreeDictionary::BinaryTreeDictionary(MemRegion mr, bool splay):
271 _splay(splay) 297 _splay(splay)
272 { 298 {
273 assert(mr.byte_size() > MIN_TREE_CHUNK_SIZE, "minimum chunk size"); 299 assert(mr.byte_size() > MIN_TREE_CHUNK_SIZE, "minimum chunk size");
274 300
377 // Change the candidate. 403 // Change the candidate.
378 curTL = hintTL; 404 curTL = hintTL;
379 break; 405 break;
380 } 406 }
381 // The evm code reset the hint of the candidate as 407 // The evm code reset the hint of the candidate as
382 // at an interrim point. Why? Seems like this leaves 408 // at an interim point. Why? Seems like this leaves
383 // the hint pointing to a list that didn't work. 409 // the hint pointing to a list that didn't work.
384 // curTL->set_hint(hintTL->size()); 410 // curTL->set_hint(hintTL->size());
385 } 411 }
386 } 412 }
387 } 413 }
434 460
435 FreeChunk* BinaryTreeDictionary::findLargestDict() const { 461 FreeChunk* BinaryTreeDictionary::findLargestDict() const {
436 TreeList *curTL = root(); 462 TreeList *curTL = root();
437 if (curTL != NULL) { 463 if (curTL != NULL) {
438 while(curTL->right() != NULL) curTL = curTL->right(); 464 while(curTL->right() != NULL) curTL = curTL->right();
439 return curTL->first_available(); 465 return curTL->largest_address();
440 } else { 466 } else {
441 return NULL; 467 return NULL;
442 } 468 }
443 } 469 }
444 470
662 assert(curTL->size() < size, "size inconsistency"); 688 assert(curTL->size() < size, "size inconsistency");
663 curTL = curTL->right(); 689 curTL = curTL->right();
664 } 690 }
665 } 691 }
666 TreeChunk* tc = TreeChunk::as_TreeChunk(fc); 692 TreeChunk* tc = TreeChunk::as_TreeChunk(fc);
667 // This chunk is being returned to the binary try. It's embedded 693 // This chunk is being returned to the binary tree. Its embedded
668 // TreeList should be unused at this point. 694 // TreeList should be unused at this point.
669 tc->initialize(); 695 tc->initialize();
670 if (curTL != NULL) { // exact match 696 if (curTL != NULL) { // exact match
671 tc->set_list(curTL); 697 tc->set_list(curTL);
672 curTL->returnChunkAtTail(tc); 698 curTL->returnChunkAtTail(tc);
805 // This is a birth associated with a LinAB. The chunk 831 // This is a birth associated with a LinAB. The chunk
806 // for the LinAB is not in the dictionary. 832 // for the LinAB is not in the dictionary.
807 } 833 }
808 834
809 bool BinaryTreeDictionary::coalDictOverPopulated(size_t size) { 835 bool BinaryTreeDictionary::coalDictOverPopulated(size_t size) {
836 if (FLSAlwaysCoalesceLarge) return true;
837
810 TreeList* list_of_size = findList(size); 838 TreeList* list_of_size = findList(size);
811 // None of requested size implies overpopulated. 839 // None of requested size implies overpopulated.
812 return list_of_size == NULL || list_of_size->coalDesired() <= 0 || 840 return list_of_size == NULL || list_of_size->coalDesired() <= 0 ||
813 list_of_size->count() > list_of_size->coalDesired(); 841 list_of_size->count() > list_of_size->coalDesired();
814 } 842 }
852 // coalesce, count before sweep, and surplus before sweep. 880 // coalesce, count before sweep, and surplus before sweep.
853 class BeginSweepClosure : public AscendTreeCensusClosure { 881 class BeginSweepClosure : public AscendTreeCensusClosure {
854 double _percentage; 882 double _percentage;
855 float _inter_sweep_current; 883 float _inter_sweep_current;
856 float _inter_sweep_estimate; 884 float _inter_sweep_estimate;
885 float _intra_sweep_estimate;
857 886
858 public: 887 public:
859 BeginSweepClosure(double p, float inter_sweep_current, 888 BeginSweepClosure(double p, float inter_sweep_current,
860 float inter_sweep_estimate) : 889 float inter_sweep_estimate,
890 float intra_sweep_estimate) :
861 _percentage(p), 891 _percentage(p),
862 _inter_sweep_current(inter_sweep_current), 892 _inter_sweep_current(inter_sweep_current),
863 _inter_sweep_estimate(inter_sweep_estimate) { } 893 _inter_sweep_estimate(inter_sweep_estimate),
894 _intra_sweep_estimate(intra_sweep_estimate) { }
864 895
865 void do_list(FreeList* fl) { 896 void do_list(FreeList* fl) {
866 double coalSurplusPercent = _percentage; 897 double coalSurplusPercent = _percentage;
867 fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate); 898 fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate);
868 fl->set_coalDesired((ssize_t)((double)fl->desired() * coalSurplusPercent)); 899 fl->set_coalDesired((ssize_t)((double)fl->desired() * coalSurplusPercent));
869 fl->set_beforeSweep(fl->count()); 900 fl->set_beforeSweep(fl->count());
870 fl->set_bfrSurp(fl->surplus()); 901 fl->set_bfrSurp(fl->surplus());
871 } 902 }
872 }; 903 };
937 assert(!found_target || etsc.found() != NULL, "Consistency check"); 968 assert(!found_target || etsc.found() != NULL, "Consistency check");
938 return etsc.found(); 969 return etsc.found();
939 } 970 }
940 971
941 void BinaryTreeDictionary::beginSweepDictCensus(double coalSurplusPercent, 972 void BinaryTreeDictionary::beginSweepDictCensus(double coalSurplusPercent,
942 float inter_sweep_current, float inter_sweep_estimate) { 973 float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) {
943 BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current, 974 BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current,
944 inter_sweep_estimate); 975 inter_sweep_estimate,
976 intra_sweep_estimate);
945 bsc.do_tree(root()); 977 bsc.do_tree(root());
946 } 978 }
947 979
948 // Closures and methods for calculating total bytes returned to the 980 // Closures and methods for calculating total bytes returned to the
949 // free lists in the tree. 981 // free lists in the tree.
1075 } 1107 }
1076 1108
1077 // Print census information - counts, births, deaths, etc. 1109 // Print census information - counts, births, deaths, etc.
1078 // for each list in the tree. Also print some summary 1110 // for each list in the tree. Also print some summary
1079 // information. 1111 // information.
1080 class printTreeCensusClosure : public AscendTreeCensusClosure { 1112 class PrintTreeCensusClosure : public AscendTreeCensusClosure {
1081 int _print_line; 1113 int _print_line;
1082 size_t _totalFree; 1114 size_t _totalFree;
1083 FreeList _total; 1115 FreeList _total;
1084 1116
1085 public: 1117 public:
1086 printTreeCensusClosure() { 1118 PrintTreeCensusClosure() {
1087 _print_line = 0; 1119 _print_line = 0;
1088 _totalFree = 0; 1120 _totalFree = 0;
1089 } 1121 }
1090 FreeList* total() { return &_total; } 1122 FreeList* total() { return &_total; }
1091 size_t totalFree() { return _totalFree; } 1123 size_t totalFree() { return _totalFree; }
1111 1143
1112 void BinaryTreeDictionary::printDictCensus(void) const { 1144 void BinaryTreeDictionary::printDictCensus(void) const {
1113 1145
1114 gclog_or_tty->print("\nBinaryTree\n"); 1146 gclog_or_tty->print("\nBinaryTree\n");
1115 FreeList::print_labels_on(gclog_or_tty, "size"); 1147 FreeList::print_labels_on(gclog_or_tty, "size");
1116 printTreeCensusClosure ptc; 1148 PrintTreeCensusClosure ptc;
1117 ptc.do_tree(root()); 1149 ptc.do_tree(root());
1118 1150
1119 FreeList* total = ptc.total(); 1151 FreeList* total = ptc.total();
1120 FreeList::print_labels_on(gclog_or_tty, " "); 1152 FreeList::print_labels_on(gclog_or_tty, " ");
1121 total->print_on(gclog_or_tty, "TOTAL\t"); 1153 total->print_on(gclog_or_tty, "TOTAL\t");
1126 (double)(total->splitBirths() + total->coalBirths() 1158 (double)(total->splitBirths() + total->coalBirths()
1127 - total->splitDeaths() - total->coalDeaths()) 1159 - total->splitDeaths() - total->coalDeaths())
1128 /(total->prevSweep() != 0 ? (double)total->prevSweep() : 1.0), 1160 /(total->prevSweep() != 0 ? (double)total->prevSweep() : 1.0),
1129 (double)(total->desired() - total->count()) 1161 (double)(total->desired() - total->count())
1130 /(total->desired() != 0 ? (double)total->desired() : 1.0)); 1162 /(total->desired() != 0 ? (double)total->desired() : 1.0));
1163 }
1164
1165 class PrintFreeListsClosure : public AscendTreeCensusClosure {
1166 outputStream* _st;
1167 int _print_line;
1168
1169 public:
1170 PrintFreeListsClosure(outputStream* st) {
1171 _st = st;
1172 _print_line = 0;
1173 }
1174 void do_list(FreeList* fl) {
1175 if (++_print_line >= 40) {
1176 FreeList::print_labels_on(_st, "size");
1177 _print_line = 0;
1178 }
1179 fl->print_on(gclog_or_tty);
1180 size_t sz = fl->size();
1181 for (FreeChunk* fc = fl->head(); fc != NULL;
1182 fc = fc->next()) {
1183 _st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s",
1184 fc, (HeapWord*)fc + sz,
1185 fc->cantCoalesce() ? "\t CC" : "");
1186 }
1187 }
1188 };
1189
1190 void BinaryTreeDictionary::print_free_lists(outputStream* st) const {
1191
1192 FreeList::print_labels_on(st, "size");
1193 PrintFreeListsClosure pflc(st);
1194 pflc.do_tree(root());
1131 } 1195 }
1132 1196
1133 // Verify the following tree invariants: 1197 // Verify the following tree invariants:
1134 // . _root has no parent 1198 // . _root has no parent
1135 // . parent and child point to each other 1199 // . parent and child point to each other