Mercurial > hg > truffle
comparison src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @ 4095:bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
Summary: Select number of GC threads dynamically based on heap usage and number of Java threads
Reviewed-by: johnc, ysr, jcoomes
author | jmasa |
---|---|
date | Tue, 09 Aug 2011 10:16:01 -0700 |
parents | a88de71c4e3a |
children | 00dd86e542eb |
comparison
equal
deleted
inserted
replaced
4094:3a298e04d914 | 4095:bca17e38de00 |
---|---|
1022 double* data) { | 1022 double* data) { |
1023 double min = data[0], max = data[0]; | 1023 double min = data[0], max = data[0]; |
1024 double total = 0.0; | 1024 double total = 0.0; |
1025 LineBuffer buf(level); | 1025 LineBuffer buf(level); |
1026 buf.append("[%s (ms):", str); | 1026 buf.append("[%s (ms):", str); |
1027 for (uint i = 0; i < ParallelGCThreads; ++i) { | 1027 for (uint i = 0; i < no_of_gc_threads(); ++i) { |
1028 double val = data[i]; | 1028 double val = data[i]; |
1029 if (val < min) | 1029 if (val < min) |
1030 min = val; | 1030 min = val; |
1031 if (val > max) | 1031 if (val > max) |
1032 max = val; | 1032 max = val; |
1033 total += val; | 1033 total += val; |
1034 buf.append(" %3.1lf", val); | 1034 buf.append(" %3.1lf", val); |
1035 } | 1035 } |
1036 buf.append_and_print_cr(""); | 1036 buf.append_and_print_cr(""); |
1037 double avg = total / (double) ParallelGCThreads; | 1037 double avg = total / (double) no_of_gc_threads(); |
1038 buf.append_and_print_cr(" Avg: %5.1lf, Min: %5.1lf, Max: %5.1lf, Diff: %5.1lf]", | 1038 buf.append_and_print_cr(" Avg: %5.1lf, Min: %5.1lf, Max: %5.1lf, Diff: %5.1lf]", |
1039 avg, min, max, max - min); | 1039 avg, min, max, max - min); |
1040 } | 1040 } |
1041 | 1041 |
1042 void G1CollectorPolicy::print_par_sizes(int level, | 1042 void G1CollectorPolicy::print_par_sizes(int level, |
1044 double* data) { | 1044 double* data) { |
1045 double min = data[0], max = data[0]; | 1045 double min = data[0], max = data[0]; |
1046 double total = 0.0; | 1046 double total = 0.0; |
1047 LineBuffer buf(level); | 1047 LineBuffer buf(level); |
1048 buf.append("[%s :", str); | 1048 buf.append("[%s :", str); |
1049 for (uint i = 0; i < ParallelGCThreads; ++i) { | 1049 for (uint i = 0; i < no_of_gc_threads(); ++i) { |
1050 double val = data[i]; | 1050 double val = data[i]; |
1051 if (val < min) | 1051 if (val < min) |
1052 min = val; | 1052 min = val; |
1053 if (val > max) | 1053 if (val > max) |
1054 max = val; | 1054 max = val; |
1055 total += val; | 1055 total += val; |
1056 buf.append(" %d", (int) val); | 1056 buf.append(" %d", (int) val); |
1057 } | 1057 } |
1058 buf.append_and_print_cr(""); | 1058 buf.append_and_print_cr(""); |
1059 double avg = total / (double) ParallelGCThreads; | 1059 double avg = total / (double) no_of_gc_threads(); |
1060 buf.append_and_print_cr(" Sum: %d, Avg: %d, Min: %d, Max: %d, Diff: %d]", | 1060 buf.append_and_print_cr(" Sum: %d, Avg: %d, Min: %d, Max: %d, Diff: %d]", |
1061 (int)total, (int)avg, (int)min, (int)max, (int)max - (int)min); | 1061 (int)total, (int)avg, (int)min, (int)max, (int)max - (int)min); |
1062 } | 1062 } |
1063 | 1063 |
1064 void G1CollectorPolicy::print_stats(int level, | 1064 void G1CollectorPolicy::print_stats(int level, |
1074 } | 1074 } |
1075 | 1075 |
1076 double G1CollectorPolicy::avg_value(double* data) { | 1076 double G1CollectorPolicy::avg_value(double* data) { |
1077 if (G1CollectedHeap::use_parallel_gc_threads()) { | 1077 if (G1CollectedHeap::use_parallel_gc_threads()) { |
1078 double ret = 0.0; | 1078 double ret = 0.0; |
1079 for (uint i = 0; i < ParallelGCThreads; ++i) { | 1079 for (uint i = 0; i < no_of_gc_threads(); ++i) { |
1080 ret += data[i]; | 1080 ret += data[i]; |
1081 } | 1081 } |
1082 return ret / (double) ParallelGCThreads; | 1082 return ret / (double) no_of_gc_threads(); |
1083 } else { | 1083 } else { |
1084 return data[0]; | 1084 return data[0]; |
1085 } | 1085 } |
1086 } | 1086 } |
1087 | 1087 |
1088 double G1CollectorPolicy::max_value(double* data) { | 1088 double G1CollectorPolicy::max_value(double* data) { |
1089 if (G1CollectedHeap::use_parallel_gc_threads()) { | 1089 if (G1CollectedHeap::use_parallel_gc_threads()) { |
1090 double ret = data[0]; | 1090 double ret = data[0]; |
1091 for (uint i = 1; i < ParallelGCThreads; ++i) { | 1091 for (uint i = 1; i < no_of_gc_threads(); ++i) { |
1092 if (data[i] > ret) { | 1092 if (data[i] > ret) { |
1093 ret = data[i]; | 1093 ret = data[i]; |
1094 } | 1094 } |
1095 } | 1095 } |
1096 return ret; | 1096 return ret; |
1100 } | 1100 } |
1101 | 1101 |
1102 double G1CollectorPolicy::sum_of_values(double* data) { | 1102 double G1CollectorPolicy::sum_of_values(double* data) { |
1103 if (G1CollectedHeap::use_parallel_gc_threads()) { | 1103 if (G1CollectedHeap::use_parallel_gc_threads()) { |
1104 double sum = 0.0; | 1104 double sum = 0.0; |
1105 for (uint i = 0; i < ParallelGCThreads; i++) { | 1105 for (uint i = 0; i < no_of_gc_threads(); i++) { |
1106 sum += data[i]; | 1106 sum += data[i]; |
1107 } | 1107 } |
1108 return sum; | 1108 return sum; |
1109 } else { | 1109 } else { |
1110 return data[0]; | 1110 return data[0]; |
1113 | 1113 |
1114 double G1CollectorPolicy::max_sum(double* data1, double* data2) { | 1114 double G1CollectorPolicy::max_sum(double* data1, double* data2) { |
1115 double ret = data1[0] + data2[0]; | 1115 double ret = data1[0] + data2[0]; |
1116 | 1116 |
1117 if (G1CollectedHeap::use_parallel_gc_threads()) { | 1117 if (G1CollectedHeap::use_parallel_gc_threads()) { |
1118 for (uint i = 1; i < ParallelGCThreads; ++i) { | 1118 for (uint i = 1; i < no_of_gc_threads(); ++i) { |
1119 double data = data1[i] + data2[i]; | 1119 double data = data1[i] + data2[i]; |
1120 if (data > ret) { | 1120 if (data > ret) { |
1121 ret = data; | 1121 ret = data; |
1122 } | 1122 } |
1123 } | 1123 } |
1126 } | 1126 } |
1127 | 1127 |
1128 // Anything below that is considered to be zero | 1128 // Anything below that is considered to be zero |
1129 #define MIN_TIMER_GRANULARITY 0.0000001 | 1129 #define MIN_TIMER_GRANULARITY 0.0000001 |
1130 | 1130 |
1131 void G1CollectorPolicy::record_collection_pause_end() { | 1131 void G1CollectorPolicy::record_collection_pause_end(int no_of_gc_threads) { |
1132 double end_time_sec = os::elapsedTime(); | 1132 double end_time_sec = os::elapsedTime(); |
1133 double elapsed_ms = _last_pause_time_ms; | 1133 double elapsed_ms = _last_pause_time_ms; |
1134 bool parallel = G1CollectedHeap::use_parallel_gc_threads(); | 1134 bool parallel = G1CollectedHeap::use_parallel_gc_threads(); |
1135 assert(_cur_collection_pause_used_regions_at_start >= cset_region_length(), | 1135 assert(_cur_collection_pause_used_regions_at_start >= cset_region_length(), |
1136 "otherwise, the subtraction below does not make sense"); | 1136 "otherwise, the subtraction below does not make sense"); |
1138 _cur_collection_pause_used_regions_at_start - cset_region_length(); | 1138 _cur_collection_pause_used_regions_at_start - cset_region_length(); |
1139 size_t cur_used_bytes = _g1->used(); | 1139 size_t cur_used_bytes = _g1->used(); |
1140 assert(cur_used_bytes == _g1->recalculate_used(), "It should!"); | 1140 assert(cur_used_bytes == _g1->recalculate_used(), "It should!"); |
1141 bool last_pause_included_initial_mark = false; | 1141 bool last_pause_included_initial_mark = false; |
1142 bool update_stats = !_g1->evacuation_failed(); | 1142 bool update_stats = !_g1->evacuation_failed(); |
1143 set_no_of_gc_threads(no_of_gc_threads); | |
1143 | 1144 |
1144 #ifndef PRODUCT | 1145 #ifndef PRODUCT |
1145 if (G1YoungSurvRateVerbose) { | 1146 if (G1YoungSurvRateVerbose) { |
1146 gclog_or_tty->print_cr(""); | 1147 gclog_or_tty->print_cr(""); |
1147 _short_lived_surv_rate_group->print(); | 1148 _short_lived_surv_rate_group->print(); |
2302 | 2303 |
2303 void work(int i) { | 2304 void work(int i) { |
2304 ParKnownGarbageHRClosure parKnownGarbageCl(_hrSorted, _chunk_size, i); | 2305 ParKnownGarbageHRClosure parKnownGarbageCl(_hrSorted, _chunk_size, i); |
2305 // Back to zero for the claim value. | 2306 // Back to zero for the claim value. |
2306 _g1->heap_region_par_iterate_chunked(&parKnownGarbageCl, i, | 2307 _g1->heap_region_par_iterate_chunked(&parKnownGarbageCl, i, |
2308 _g1->workers()->active_workers(), | |
2307 HeapRegion::InitialClaimValue); | 2309 HeapRegion::InitialClaimValue); |
2308 jint regions_added = parKnownGarbageCl.marked_regions_added(); | 2310 jint regions_added = parKnownGarbageCl.marked_regions_added(); |
2309 _hrSorted->incNumMarkedHeapRegions(regions_added); | 2311 _hrSorted->incNumMarkedHeapRegions(regions_added); |
2310 if (G1PrintParCleanupStats) { | 2312 if (G1PrintParCleanupStats) { |
2311 gclog_or_tty->print_cr(" Thread %d called %d times, added %d regions to list.", | 2313 gclog_or_tty->print_cr(" Thread %d called %d times, added %d regions to list.", |
2313 } | 2315 } |
2314 } | 2316 } |
2315 }; | 2317 }; |
2316 | 2318 |
2317 void | 2319 void |
2318 G1CollectorPolicy::record_concurrent_mark_cleanup_end() { | 2320 G1CollectorPolicy::record_concurrent_mark_cleanup_end(int no_of_gc_threads) { |
2319 double start_sec; | 2321 double start_sec; |
2320 if (G1PrintParCleanupStats) { | 2322 if (G1PrintParCleanupStats) { |
2321 start_sec = os::elapsedTime(); | 2323 start_sec = os::elapsedTime(); |
2322 } | 2324 } |
2323 | 2325 |
2329 (clear_marked_end_sec - start_sec) * 1000.0); | 2331 (clear_marked_end_sec - start_sec) * 1000.0); |
2330 } | 2332 } |
2331 | 2333 |
2332 if (G1CollectedHeap::use_parallel_gc_threads()) { | 2334 if (G1CollectedHeap::use_parallel_gc_threads()) { |
2333 const size_t OverpartitionFactor = 4; | 2335 const size_t OverpartitionFactor = 4; |
2334 const size_t MinWorkUnit = 8; | 2336 size_t WorkUnit; |
2335 const size_t WorkUnit = | 2337 // The use of MinChunkSize = 8 in the original code |
2336 MAX2(_g1->n_regions() / (ParallelGCThreads * OverpartitionFactor), | 2338 // causes some assertion failures when the total number of |
2337 MinWorkUnit); | 2339 // region is less than 8. The code here tries to fix that. |
2340 // Should the original code also be fixed? | |
2341 if (no_of_gc_threads > 0) { | |
2342 const size_t MinWorkUnit = | |
2343 MAX2(_g1->n_regions() / no_of_gc_threads, (size_t) 1U); | |
2344 WorkUnit = | |
2345 MAX2(_g1->n_regions() / (no_of_gc_threads * OverpartitionFactor), | |
2346 MinWorkUnit); | |
2347 } else { | |
2348 assert(no_of_gc_threads > 0, | |
2349 "The active gc workers should be greater than 0"); | |
2350 // In a product build do something reasonable to avoid a crash. | |
2351 const size_t MinWorkUnit = | |
2352 MAX2(_g1->n_regions() / ParallelGCThreads, (size_t) 1U); | |
2353 WorkUnit = | |
2354 MAX2(_g1->n_regions() / (ParallelGCThreads * OverpartitionFactor), | |
2355 MinWorkUnit); | |
2356 } | |
2338 _collectionSetChooser->prepareForAddMarkedHeapRegionsPar(_g1->n_regions(), | 2357 _collectionSetChooser->prepareForAddMarkedHeapRegionsPar(_g1->n_regions(), |
2339 WorkUnit); | 2358 WorkUnit); |
2340 ParKnownGarbageTask parKnownGarbageTask(_collectionSetChooser, | 2359 ParKnownGarbageTask parKnownGarbageTask(_collectionSetChooser, |
2341 (int) WorkUnit); | 2360 (int) WorkUnit); |
2342 _g1->workers()->run_task(&parKnownGarbageTask); | 2361 _g1->workers()->run_task(&parKnownGarbageTask); |