Mercurial > hg > graal-compiler
annotate src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp @ 795:215f81b4d9b3
6841831: G1: assert(contains_reference(from),"We just added it!") fires
Summary: During parallel rset updating we have to make sure that the worker ids of the refinement threads do not intersect with the worker ids that can be claimed by the mutator threads.
Reviewed-by: tonyp
author | iveresov |
---|---|
date | Mon, 18 May 2009 11:52:46 -0700 |
parents | 315a5d70b295 |
children | 0316eac49d5a |
rev | line source |
---|---|
342 | 1 /* |
579 | 2 * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. |
342 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
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 | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
20 * CA 95054 USA or visit www.sun.com if you need additional information or | |
21 * have any questions. | |
22 * | |
23 */ | |
24 | |
25 // A G1CollectorPolicy makes policy decisions that determine the | |
26 // characteristics of the collector. Examples include: | |
27 // * choice of collection set. | |
28 // * when to collect. | |
29 | |
30 class HeapRegion; | |
31 class CollectionSetChooser; | |
32 | |
33 // Yes, this is a bit unpleasant... but it saves replicating the same thing | |
34 // over and over again and introducing subtle problems through small typos and | |
35 // cutting and pasting mistakes. The macros below introduces a number | |
36 // sequnce into the following two classes and the methods that access it. | |
37 | |
38 #define define_num_seq(name) \ | |
39 private: \ | |
40 NumberSeq _all_##name##_times_ms; \ | |
41 public: \ | |
42 void record_##name##_time_ms(double ms) { \ | |
43 _all_##name##_times_ms.add(ms); \ | |
44 } \ | |
45 NumberSeq* get_##name##_seq() { \ | |
46 return &_all_##name##_times_ms; \ | |
47 } | |
48 | |
49 class MainBodySummary; | |
50 | |
549
fe3d7c11b4b7
6700941: G1: allocation spec missing for some G1 classes
apetrusenko
parents:
545
diff
changeset
|
51 class PauseSummary: public CHeapObj { |
342 | 52 define_num_seq(total) |
53 define_num_seq(other) | |
54 | |
55 public: | |
56 virtual MainBodySummary* main_body_summary() { return NULL; } | |
57 }; | |
58 | |
549
fe3d7c11b4b7
6700941: G1: allocation spec missing for some G1 classes
apetrusenko
parents:
545
diff
changeset
|
59 class MainBodySummary: public CHeapObj { |
342 | 60 define_num_seq(satb_drain) // optional |
61 define_num_seq(parallel) // parallel only | |
62 define_num_seq(ext_root_scan) | |
63 define_num_seq(mark_stack_scan) | |
64 define_num_seq(scan_only) | |
65 define_num_seq(update_rs) | |
66 define_num_seq(scan_rs) | |
67 define_num_seq(scan_new_refs) // Only for temp use; added to | |
68 // in parallel case. | |
69 define_num_seq(obj_copy) | |
70 define_num_seq(termination) // parallel only | |
71 define_num_seq(parallel_other) // parallel only | |
72 define_num_seq(mark_closure) | |
73 define_num_seq(clear_ct) // parallel only | |
74 }; | |
75 | |
677 | 76 class Summary: public PauseSummary, |
77 public MainBodySummary { | |
342 | 78 public: |
79 virtual MainBodySummary* main_body_summary() { return this; } | |
80 }; | |
81 | |
677 | 82 class AbandonedSummary: public PauseSummary { |
342 | 83 }; |
84 | |
85 class G1CollectorPolicy: public CollectorPolicy { | |
86 protected: | |
87 // The number of pauses during the execution. | |
88 long _n_pauses; | |
89 | |
90 // either equal to the number of parallel threads, if ParallelGCThreads | |
91 // has been set, or 1 otherwise | |
92 int _parallel_gc_threads; | |
93 | |
94 enum SomePrivateConstants { | |
95 NumPrevPausesForHeuristics = 10, | |
96 NumPrevGCsForHeuristics = 10, | |
97 NumAPIs = HeapRegion::MaxAge | |
98 }; | |
99 | |
100 G1MMUTracker* _mmu_tracker; | |
101 | |
102 void initialize_flags(); | |
103 | |
104 void initialize_all() { | |
105 initialize_flags(); | |
106 initialize_size_info(); | |
107 initialize_perm_generation(PermGen::MarkSweepCompact); | |
108 } | |
109 | |
110 virtual size_t default_init_heap_size() { | |
111 // Pick some reasonable default. | |
112 return 8*M; | |
113 } | |
114 | |
115 | |
116 double _cur_collection_start_sec; | |
117 size_t _cur_collection_pause_used_at_start_bytes; | |
118 size_t _cur_collection_pause_used_regions_at_start; | |
119 size_t _prev_collection_pause_used_at_end_bytes; | |
120 double _cur_collection_par_time_ms; | |
121 double _cur_satb_drain_time_ms; | |
122 double _cur_clear_ct_time_ms; | |
123 bool _satb_drain_time_set; | |
124 | |
125 double _cur_CH_strong_roots_end_sec; | |
126 double _cur_CH_strong_roots_dur_ms; | |
127 double _cur_G1_strong_roots_end_sec; | |
128 double _cur_G1_strong_roots_dur_ms; | |
129 | |
130 // Statistics for recent GC pauses. See below for how indexed. | |
131 TruncatedSeq* _recent_CH_strong_roots_times_ms; | |
132 TruncatedSeq* _recent_G1_strong_roots_times_ms; | |
133 TruncatedSeq* _recent_evac_times_ms; | |
134 // These exclude marking times. | |
135 TruncatedSeq* _recent_pause_times_ms; | |
136 TruncatedSeq* _recent_gc_times_ms; | |
137 | |
138 TruncatedSeq* _recent_CS_bytes_used_before; | |
139 TruncatedSeq* _recent_CS_bytes_surviving; | |
140 | |
141 TruncatedSeq* _recent_rs_sizes; | |
142 | |
143 TruncatedSeq* _concurrent_mark_init_times_ms; | |
144 TruncatedSeq* _concurrent_mark_remark_times_ms; | |
145 TruncatedSeq* _concurrent_mark_cleanup_times_ms; | |
146 | |
677 | 147 Summary* _summary; |
148 AbandonedSummary* _abandoned_summary; | |
342 | 149 |
150 NumberSeq* _all_pause_times_ms; | |
151 NumberSeq* _all_full_gc_times_ms; | |
152 double _stop_world_start; | |
153 NumberSeq* _all_stop_world_times_ms; | |
154 NumberSeq* _all_yield_times_ms; | |
155 | |
156 size_t _region_num_young; | |
157 size_t _region_num_tenured; | |
158 size_t _prev_region_num_young; | |
159 size_t _prev_region_num_tenured; | |
160 | |
161 NumberSeq* _all_mod_union_times_ms; | |
162 | |
163 int _aux_num; | |
164 NumberSeq* _all_aux_times_ms; | |
165 double* _cur_aux_start_times_ms; | |
166 double* _cur_aux_times_ms; | |
167 bool* _cur_aux_times_set; | |
168 | |
169 double* _par_last_ext_root_scan_times_ms; | |
170 double* _par_last_mark_stack_scan_times_ms; | |
171 double* _par_last_scan_only_times_ms; | |
172 double* _par_last_scan_only_regions_scanned; | |
173 double* _par_last_update_rs_start_times_ms; | |
174 double* _par_last_update_rs_times_ms; | |
175 double* _par_last_update_rs_processed_buffers; | |
176 double* _par_last_scan_rs_start_times_ms; | |
177 double* _par_last_scan_rs_times_ms; | |
178 double* _par_last_scan_new_refs_times_ms; | |
179 double* _par_last_obj_copy_times_ms; | |
180 double* _par_last_termination_times_ms; | |
181 | |
182 // indicates that we are in young GC mode | |
183 bool _in_young_gc_mode; | |
184 | |
185 // indicates whether we are in full young or partially young GC mode | |
186 bool _full_young_gcs; | |
187 | |
188 // if true, then it tries to dynamically adjust the length of the | |
189 // young list | |
190 bool _adaptive_young_list_length; | |
191 size_t _young_list_min_length; | |
192 size_t _young_list_target_length; | |
193 size_t _young_list_so_prefix_length; | |
194 size_t _young_list_fixed_length; | |
195 | |
196 size_t _young_cset_length; | |
197 bool _last_young_gc_full; | |
198 | |
199 double _target_pause_time_ms; | |
200 | |
201 unsigned _full_young_pause_num; | |
202 unsigned _partial_young_pause_num; | |
203 | |
204 bool _during_marking; | |
205 bool _in_marking_window; | |
206 bool _in_marking_window_im; | |
207 | |
208 SurvRateGroup* _short_lived_surv_rate_group; | |
209 SurvRateGroup* _survivor_surv_rate_group; | |
210 // add here any more surv rate groups | |
211 | |
212 bool during_marking() { | |
213 return _during_marking; | |
214 } | |
215 | |
216 // <NEW PREDICTION> | |
217 | |
218 private: | |
219 enum PredictionConstants { | |
220 TruncatedSeqLength = 10 | |
221 }; | |
222 | |
223 TruncatedSeq* _alloc_rate_ms_seq; | |
224 double _prev_collection_pause_end_ms; | |
225 | |
226 TruncatedSeq* _pending_card_diff_seq; | |
227 TruncatedSeq* _rs_length_diff_seq; | |
228 TruncatedSeq* _cost_per_card_ms_seq; | |
229 TruncatedSeq* _cost_per_scan_only_region_ms_seq; | |
230 TruncatedSeq* _fully_young_cards_per_entry_ratio_seq; | |
231 TruncatedSeq* _partially_young_cards_per_entry_ratio_seq; | |
232 TruncatedSeq* _cost_per_entry_ms_seq; | |
233 TruncatedSeq* _partially_young_cost_per_entry_ms_seq; | |
234 TruncatedSeq* _cost_per_byte_ms_seq; | |
235 TruncatedSeq* _constant_other_time_ms_seq; | |
236 TruncatedSeq* _young_other_cost_per_region_ms_seq; | |
237 TruncatedSeq* _non_young_other_cost_per_region_ms_seq; | |
238 | |
239 TruncatedSeq* _pending_cards_seq; | |
240 TruncatedSeq* _scanned_cards_seq; | |
241 TruncatedSeq* _rs_lengths_seq; | |
242 | |
243 TruncatedSeq* _cost_per_byte_ms_during_cm_seq; | |
244 TruncatedSeq* _cost_per_scan_only_region_ms_during_cm_seq; | |
245 | |
246 TruncatedSeq* _young_gc_eff_seq; | |
247 | |
248 TruncatedSeq* _max_conc_overhead_seq; | |
249 | |
250 size_t _recorded_young_regions; | |
251 size_t _recorded_scan_only_regions; | |
252 size_t _recorded_non_young_regions; | |
253 size_t _recorded_region_num; | |
254 | |
255 size_t _free_regions_at_end_of_collection; | |
256 size_t _scan_only_regions_at_end_of_collection; | |
257 | |
258 size_t _recorded_rs_lengths; | |
259 size_t _max_rs_lengths; | |
260 | |
261 size_t _recorded_marked_bytes; | |
262 size_t _recorded_young_bytes; | |
263 | |
264 size_t _predicted_pending_cards; | |
265 size_t _predicted_cards_scanned; | |
266 size_t _predicted_rs_lengths; | |
267 size_t _predicted_bytes_to_copy; | |
268 | |
269 double _predicted_survival_ratio; | |
270 double _predicted_rs_update_time_ms; | |
271 double _predicted_rs_scan_time_ms; | |
272 double _predicted_scan_only_scan_time_ms; | |
273 double _predicted_object_copy_time_ms; | |
274 double _predicted_constant_other_time_ms; | |
275 double _predicted_young_other_time_ms; | |
276 double _predicted_non_young_other_time_ms; | |
277 double _predicted_pause_time_ms; | |
278 | |
279 double _vtime_diff_ms; | |
280 | |
281 double _recorded_young_free_cset_time_ms; | |
282 double _recorded_non_young_free_cset_time_ms; | |
283 | |
284 double _sigma; | |
285 double _expensive_region_limit_ms; | |
286 | |
287 size_t _rs_lengths_prediction; | |
288 | |
289 size_t _known_garbage_bytes; | |
290 double _known_garbage_ratio; | |
291 | |
292 double sigma() { | |
293 return _sigma; | |
294 } | |
295 | |
296 // A function that prevents us putting too much stock in small sample | |
297 // sets. Returns a number between 2.0 and 1.0, depending on the number | |
298 // of samples. 5 or more samples yields one; fewer scales linearly from | |
299 // 2.0 at 1 sample to 1.0 at 5. | |
300 double confidence_factor(int samples) { | |
301 if (samples > 4) return 1.0; | |
302 else return 1.0 + sigma() * ((double)(5 - samples))/2.0; | |
303 } | |
304 | |
305 double get_new_neg_prediction(TruncatedSeq* seq) { | |
306 return seq->davg() - sigma() * seq->dsd(); | |
307 } | |
308 | |
309 #ifndef PRODUCT | |
310 bool verify_young_ages(HeapRegion* head, SurvRateGroup *surv_rate_group); | |
311 #endif // PRODUCT | |
312 | |
313 protected: | |
314 double _pause_time_target_ms; | |
315 double _recorded_young_cset_choice_time_ms; | |
316 double _recorded_non_young_cset_choice_time_ms; | |
317 bool _within_target; | |
318 size_t _pending_cards; | |
319 size_t _max_pending_cards; | |
320 | |
321 public: | |
322 | |
323 void set_region_short_lived(HeapRegion* hr) { | |
324 hr->install_surv_rate_group(_short_lived_surv_rate_group); | |
325 } | |
326 | |
327 void set_region_survivors(HeapRegion* hr) { | |
328 hr->install_surv_rate_group(_survivor_surv_rate_group); | |
329 } | |
330 | |
331 #ifndef PRODUCT | |
332 bool verify_young_ages(); | |
333 #endif // PRODUCT | |
334 | |
335 void tag_scan_only(size_t short_lived_scan_only_length); | |
336 | |
337 double get_new_prediction(TruncatedSeq* seq) { | |
338 return MAX2(seq->davg() + sigma() * seq->dsd(), | |
339 seq->davg() * confidence_factor(seq->num())); | |
340 } | |
341 | |
342 size_t young_cset_length() { | |
343 return _young_cset_length; | |
344 } | |
345 | |
346 void record_max_rs_lengths(size_t rs_lengths) { | |
347 _max_rs_lengths = rs_lengths; | |
348 } | |
349 | |
350 size_t predict_pending_card_diff() { | |
351 double prediction = get_new_neg_prediction(_pending_card_diff_seq); | |
352 if (prediction < 0.00001) | |
353 return 0; | |
354 else | |
355 return (size_t) prediction; | |
356 } | |
357 | |
358 size_t predict_pending_cards() { | |
359 size_t max_pending_card_num = _g1->max_pending_card_num(); | |
360 size_t diff = predict_pending_card_diff(); | |
361 size_t prediction; | |
362 if (diff > max_pending_card_num) | |
363 prediction = max_pending_card_num; | |
364 else | |
365 prediction = max_pending_card_num - diff; | |
366 | |
367 return prediction; | |
368 } | |
369 | |
370 size_t predict_rs_length_diff() { | |
371 return (size_t) get_new_prediction(_rs_length_diff_seq); | |
372 } | |
373 | |
374 double predict_alloc_rate_ms() { | |
375 return get_new_prediction(_alloc_rate_ms_seq); | |
376 } | |
377 | |
378 double predict_cost_per_card_ms() { | |
379 return get_new_prediction(_cost_per_card_ms_seq); | |
380 } | |
381 | |
382 double predict_rs_update_time_ms(size_t pending_cards) { | |
383 return (double) pending_cards * predict_cost_per_card_ms(); | |
384 } | |
385 | |
386 double predict_fully_young_cards_per_entry_ratio() { | |
387 return get_new_prediction(_fully_young_cards_per_entry_ratio_seq); | |
388 } | |
389 | |
390 double predict_partially_young_cards_per_entry_ratio() { | |
391 if (_partially_young_cards_per_entry_ratio_seq->num() < 2) | |
392 return predict_fully_young_cards_per_entry_ratio(); | |
393 else | |
394 return get_new_prediction(_partially_young_cards_per_entry_ratio_seq); | |
395 } | |
396 | |
397 size_t predict_young_card_num(size_t rs_length) { | |
398 return (size_t) ((double) rs_length * | |
399 predict_fully_young_cards_per_entry_ratio()); | |
400 } | |
401 | |
402 size_t predict_non_young_card_num(size_t rs_length) { | |
403 return (size_t) ((double) rs_length * | |
404 predict_partially_young_cards_per_entry_ratio()); | |
405 } | |
406 | |
407 double predict_rs_scan_time_ms(size_t card_num) { | |
408 if (full_young_gcs()) | |
409 return (double) card_num * get_new_prediction(_cost_per_entry_ms_seq); | |
410 else | |
411 return predict_partially_young_rs_scan_time_ms(card_num); | |
412 } | |
413 | |
414 double predict_partially_young_rs_scan_time_ms(size_t card_num) { | |
415 if (_partially_young_cost_per_entry_ms_seq->num() < 3) | |
416 return (double) card_num * get_new_prediction(_cost_per_entry_ms_seq); | |
417 else | |
418 return (double) card_num * | |
419 get_new_prediction(_partially_young_cost_per_entry_ms_seq); | |
420 } | |
421 | |
422 double predict_scan_only_time_ms_during_cm(size_t scan_only_region_num) { | |
423 if (_cost_per_scan_only_region_ms_during_cm_seq->num() < 3) | |
424 return 1.5 * (double) scan_only_region_num * | |
425 get_new_prediction(_cost_per_scan_only_region_ms_seq); | |
426 else | |
427 return (double) scan_only_region_num * | |
428 get_new_prediction(_cost_per_scan_only_region_ms_during_cm_seq); | |
429 } | |
430 | |
431 double predict_scan_only_time_ms(size_t scan_only_region_num) { | |
432 if (_in_marking_window_im) | |
433 return predict_scan_only_time_ms_during_cm(scan_only_region_num); | |
434 else | |
435 return (double) scan_only_region_num * | |
436 get_new_prediction(_cost_per_scan_only_region_ms_seq); | |
437 } | |
438 | |
439 double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) { | |
440 if (_cost_per_byte_ms_during_cm_seq->num() < 3) | |
441 return 1.1 * (double) bytes_to_copy * | |
442 get_new_prediction(_cost_per_byte_ms_seq); | |
443 else | |
444 return (double) bytes_to_copy * | |
445 get_new_prediction(_cost_per_byte_ms_during_cm_seq); | |
446 } | |
447 | |
448 double predict_object_copy_time_ms(size_t bytes_to_copy) { | |
449 if (_in_marking_window && !_in_marking_window_im) | |
450 return predict_object_copy_time_ms_during_cm(bytes_to_copy); | |
451 else | |
452 return (double) bytes_to_copy * | |
453 get_new_prediction(_cost_per_byte_ms_seq); | |
454 } | |
455 | |
456 double predict_constant_other_time_ms() { | |
457 return get_new_prediction(_constant_other_time_ms_seq); | |
458 } | |
459 | |
460 double predict_young_other_time_ms(size_t young_num) { | |
461 return | |
462 (double) young_num * | |
463 get_new_prediction(_young_other_cost_per_region_ms_seq); | |
464 } | |
465 | |
466 double predict_non_young_other_time_ms(size_t non_young_num) { | |
467 return | |
468 (double) non_young_num * | |
469 get_new_prediction(_non_young_other_cost_per_region_ms_seq); | |
470 } | |
471 | |
472 void check_if_region_is_too_expensive(double predicted_time_ms); | |
473 | |
474 double predict_young_collection_elapsed_time_ms(size_t adjustment); | |
475 double predict_base_elapsed_time_ms(size_t pending_cards); | |
476 double predict_base_elapsed_time_ms(size_t pending_cards, | |
477 size_t scanned_cards); | |
478 size_t predict_bytes_to_copy(HeapRegion* hr); | |
479 double predict_region_elapsed_time_ms(HeapRegion* hr, bool young); | |
480 | |
481 // for use by: calculate_optimal_so_length(length) | |
482 void predict_gc_eff(size_t young_region_num, | |
483 size_t so_length, | |
484 double base_time_ms, | |
485 double *gc_eff, | |
486 double *pause_time_ms); | |
487 | |
488 // for use by: calculate_young_list_target_config(rs_length) | |
489 bool predict_gc_eff(size_t young_region_num, | |
490 size_t so_length, | |
491 double base_time_with_so_ms, | |
492 size_t init_free_regions, | |
493 double target_pause_time_ms, | |
494 double* gc_eff); | |
495 | |
496 void start_recording_regions(); | |
497 void record_cset_region(HeapRegion* hr, bool young); | |
498 void record_scan_only_regions(size_t scan_only_length); | |
499 void end_recording_regions(); | |
500 | |
501 void record_vtime_diff_ms(double vtime_diff_ms) { | |
502 _vtime_diff_ms = vtime_diff_ms; | |
503 } | |
504 | |
505 void record_young_free_cset_time_ms(double time_ms) { | |
506 _recorded_young_free_cset_time_ms = time_ms; | |
507 } | |
508 | |
509 void record_non_young_free_cset_time_ms(double time_ms) { | |
510 _recorded_non_young_free_cset_time_ms = time_ms; | |
511 } | |
512 | |
513 double predict_young_gc_eff() { | |
514 return get_new_neg_prediction(_young_gc_eff_seq); | |
515 } | |
516 | |
545 | 517 double predict_survivor_regions_evac_time(); |
518 | |
342 | 519 // </NEW PREDICTION> |
520 | |
521 public: | |
522 void cset_regions_freed() { | |
523 bool propagate = _last_young_gc_full && !_in_marking_window; | |
524 _short_lived_surv_rate_group->all_surviving_words_recorded(propagate); | |
525 _survivor_surv_rate_group->all_surviving_words_recorded(propagate); | |
526 // also call it on any more surv rate groups | |
527 } | |
528 | |
529 void set_known_garbage_bytes(size_t known_garbage_bytes) { | |
530 _known_garbage_bytes = known_garbage_bytes; | |
531 size_t heap_bytes = _g1->capacity(); | |
532 _known_garbage_ratio = (double) _known_garbage_bytes / (double) heap_bytes; | |
533 } | |
534 | |
535 void decrease_known_garbage_bytes(size_t known_garbage_bytes) { | |
536 guarantee( _known_garbage_bytes >= known_garbage_bytes, "invariant" ); | |
537 | |
538 _known_garbage_bytes -= known_garbage_bytes; | |
539 size_t heap_bytes = _g1->capacity(); | |
540 _known_garbage_ratio = (double) _known_garbage_bytes / (double) heap_bytes; | |
541 } | |
542 | |
543 G1MMUTracker* mmu_tracker() { | |
544 return _mmu_tracker; | |
545 } | |
546 | |
547 double predict_init_time_ms() { | |
548 return get_new_prediction(_concurrent_mark_init_times_ms); | |
549 } | |
550 | |
551 double predict_remark_time_ms() { | |
552 return get_new_prediction(_concurrent_mark_remark_times_ms); | |
553 } | |
554 | |
555 double predict_cleanup_time_ms() { | |
556 return get_new_prediction(_concurrent_mark_cleanup_times_ms); | |
557 } | |
558 | |
559 // Returns an estimate of the survival rate of the region at yg-age | |
560 // "yg_age". | |
545 | 561 double predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) { |
562 TruncatedSeq* seq = surv_rate_group->get_seq(age); | |
342 | 563 if (seq->num() == 0) |
564 gclog_or_tty->print("BARF! age is %d", age); | |
565 guarantee( seq->num() > 0, "invariant" ); | |
566 double pred = get_new_prediction(seq); | |
567 if (pred > 1.0) | |
568 pred = 1.0; | |
569 return pred; | |
570 } | |
571 | |
545 | 572 double predict_yg_surv_rate(int age) { |
573 return predict_yg_surv_rate(age, _short_lived_surv_rate_group); | |
574 } | |
575 | |
342 | 576 double accum_yg_surv_rate_pred(int age) { |
577 return _short_lived_surv_rate_group->accum_surv_rate_pred(age); | |
578 } | |
579 | |
580 protected: | |
581 void print_stats (int level, const char* str, double value); | |
582 void print_stats (int level, const char* str, int value); | |
583 void print_par_stats (int level, const char* str, double* data) { | |
584 print_par_stats(level, str, data, true); | |
585 } | |
586 void print_par_stats (int level, const char* str, double* data, bool summary); | |
587 void print_par_buffers (int level, const char* str, double* data, bool summary); | |
588 | |
589 void check_other_times(int level, | |
590 NumberSeq* other_times_ms, | |
591 NumberSeq* calc_other_times_ms) const; | |
592 | |
593 void print_summary (PauseSummary* stats) const; | |
677 | 594 void print_abandoned_summary(PauseSummary* summary) const; |
342 | 595 |
596 void print_summary (int level, const char* str, NumberSeq* seq) const; | |
597 void print_summary_sd (int level, const char* str, NumberSeq* seq) const; | |
598 | |
599 double avg_value (double* data); | |
600 double max_value (double* data); | |
601 double sum_of_values (double* data); | |
602 double max_sum (double* data1, double* data2); | |
603 | |
604 int _last_satb_drain_processed_buffers; | |
605 int _last_update_rs_processed_buffers; | |
606 double _last_pause_time_ms; | |
607 | |
608 size_t _bytes_in_to_space_before_gc; | |
609 size_t _bytes_in_to_space_after_gc; | |
610 size_t bytes_in_to_space_during_gc() { | |
611 return | |
612 _bytes_in_to_space_after_gc - _bytes_in_to_space_before_gc; | |
613 } | |
614 size_t _bytes_in_collection_set_before_gc; | |
615 // Used to count used bytes in CS. | |
616 friend class CountCSClosure; | |
617 | |
618 // Statistics kept per GC stoppage, pause or full. | |
619 TruncatedSeq* _recent_prev_end_times_for_all_gcs_sec; | |
620 | |
621 // We track markings. | |
622 int _num_markings; | |
623 double _mark_thread_startup_sec; // Time at startup of marking thread | |
624 | |
625 // Add a new GC of the given duration and end time to the record. | |
626 void update_recent_gc_times(double end_time_sec, double elapsed_ms); | |
627 | |
628 // The head of the list (via "next_in_collection_set()") representing the | |
629 // current collection set. | |
630 HeapRegion* _collection_set; | |
631 size_t _collection_set_size; | |
632 size_t _collection_set_bytes_used_before; | |
633 | |
634 // Info about marking. | |
635 int _n_marks; // Sticky at 2, so we know when we've done at least 2. | |
636 | |
637 // The number of collection pauses at the end of the last mark. | |
638 size_t _n_pauses_at_mark_end; | |
639 | |
640 // Stash a pointer to the g1 heap. | |
641 G1CollectedHeap* _g1; | |
642 | |
643 // The average time in ms per collection pause, averaged over recent pauses. | |
644 double recent_avg_time_for_pauses_ms(); | |
645 | |
646 // The average time in ms for processing CollectedHeap strong roots, per | |
647 // collection pause, averaged over recent pauses. | |
648 double recent_avg_time_for_CH_strong_ms(); | |
649 | |
650 // The average time in ms for processing the G1 remembered set, per | |
651 // pause, averaged over recent pauses. | |
652 double recent_avg_time_for_G1_strong_ms(); | |
653 | |
654 // The average time in ms for "evacuating followers", per pause, averaged | |
655 // over recent pauses. | |
656 double recent_avg_time_for_evac_ms(); | |
657 | |
658 // The number of "recent" GCs recorded in the number sequences | |
659 int number_of_recent_gcs(); | |
660 | |
661 // The average survival ratio, computed by the total number of bytes | |
662 // suriviving / total number of bytes before collection over the last | |
663 // several recent pauses. | |
664 double recent_avg_survival_fraction(); | |
665 // The survival fraction of the most recent pause; if there have been no | |
666 // pauses, returns 1.0. | |
667 double last_survival_fraction(); | |
668 | |
669 // Returns a "conservative" estimate of the recent survival rate, i.e., | |
670 // one that may be higher than "recent_avg_survival_fraction". | |
671 // This is conservative in several ways: | |
672 // If there have been few pauses, it will assume a potential high | |
673 // variance, and err on the side of caution. | |
674 // It puts a lower bound (currently 0.1) on the value it will return. | |
675 // To try to detect phase changes, if the most recent pause ("latest") has a | |
676 // higher-than average ("avg") survival rate, it returns that rate. | |
677 // "work" version is a utility function; young is restricted to young regions. | |
678 double conservative_avg_survival_fraction_work(double avg, | |
679 double latest); | |
680 | |
681 // The arguments are the two sequences that keep track of the number of bytes | |
682 // surviving and the total number of bytes before collection, resp., | |
683 // over the last evereal recent pauses | |
684 // Returns the survival rate for the category in the most recent pause. | |
685 // If there have been no pauses, returns 1.0. | |
686 double last_survival_fraction_work(TruncatedSeq* surviving, | |
687 TruncatedSeq* before); | |
688 | |
689 // The arguments are the two sequences that keep track of the number of bytes | |
690 // surviving and the total number of bytes before collection, resp., | |
691 // over the last several recent pauses | |
692 // Returns the average survival ration over the last several recent pauses | |
693 // If there have been no pauses, return 1.0 | |
694 double recent_avg_survival_fraction_work(TruncatedSeq* surviving, | |
695 TruncatedSeq* before); | |
696 | |
697 double conservative_avg_survival_fraction() { | |
698 double avg = recent_avg_survival_fraction(); | |
699 double latest = last_survival_fraction(); | |
700 return conservative_avg_survival_fraction_work(avg, latest); | |
701 } | |
702 | |
703 // The ratio of gc time to elapsed time, computed over recent pauses. | |
704 double _recent_avg_pause_time_ratio; | |
705 | |
706 double recent_avg_pause_time_ratio() { | |
707 return _recent_avg_pause_time_ratio; | |
708 } | |
709 | |
710 // Number of pauses between concurrent marking. | |
711 size_t _pauses_btwn_concurrent_mark; | |
712 | |
713 size_t _n_marks_since_last_pause; | |
714 | |
715 // True iff CM has been initiated. | |
716 bool _conc_mark_initiated; | |
717 | |
718 // True iff CM should be initiated | |
719 bool _should_initiate_conc_mark; | |
720 bool _should_revert_to_full_young_gcs; | |
721 bool _last_full_young_gc; | |
722 | |
723 // This set of variables tracks the collector efficiency, in order to | |
724 // determine whether we should initiate a new marking. | |
725 double _cur_mark_stop_world_time_ms; | |
726 double _mark_init_start_sec; | |
727 double _mark_remark_start_sec; | |
728 double _mark_cleanup_start_sec; | |
729 double _mark_closure_time_ms; | |
730 | |
731 void calculate_young_list_min_length(); | |
732 void calculate_young_list_target_config(); | |
733 void calculate_young_list_target_config(size_t rs_lengths); | |
734 size_t calculate_optimal_so_length(size_t young_list_length); | |
735 | |
736 public: | |
737 | |
738 G1CollectorPolicy(); | |
739 | |
740 virtual G1CollectorPolicy* as_g1_policy() { return this; } | |
741 | |
742 virtual CollectorPolicy::Name kind() { | |
743 return CollectorPolicy::G1CollectorPolicyKind; | |
744 } | |
745 | |
746 void check_prediction_validity(); | |
747 | |
748 size_t bytes_in_collection_set() { | |
749 return _bytes_in_collection_set_before_gc; | |
750 } | |
751 | |
752 size_t bytes_in_to_space() { | |
753 return bytes_in_to_space_during_gc(); | |
754 } | |
755 | |
756 unsigned calc_gc_alloc_time_stamp() { | |
757 return _all_pause_times_ms->num() + 1; | |
758 } | |
759 | |
760 protected: | |
761 | |
762 // Count the number of bytes used in the CS. | |
763 void count_CS_bytes_used(); | |
764 | |
765 // Together these do the base cleanup-recording work. Subclasses might | |
766 // want to put something between them. | |
767 void record_concurrent_mark_cleanup_end_work1(size_t freed_bytes, | |
768 size_t max_live_bytes); | |
769 void record_concurrent_mark_cleanup_end_work2(); | |
770 | |
771 public: | |
772 | |
773 virtual void init(); | |
774 | |
545 | 775 // Create jstat counters for the policy. |
776 virtual void initialize_gc_policy_counters(); | |
777 | |
342 | 778 virtual HeapWord* mem_allocate_work(size_t size, |
779 bool is_tlab, | |
780 bool* gc_overhead_limit_was_exceeded); | |
781 | |
782 // This method controls how a collector handles one or more | |
783 // of its generations being fully allocated. | |
784 virtual HeapWord* satisfy_failed_allocation(size_t size, | |
785 bool is_tlab); | |
786 | |
787 BarrierSet::Name barrier_set_name() { return BarrierSet::G1SATBCTLogging; } | |
788 | |
789 GenRemSet::Name rem_set_name() { return GenRemSet::CardTable; } | |
790 | |
791 // The number of collection pauses so far. | |
792 long n_pauses() const { return _n_pauses; } | |
793 | |
794 // Update the heuristic info to record a collection pause of the given | |
795 // start time, where the given number of bytes were used at the start. | |
796 // This may involve changing the desired size of a collection set. | |
797 | |
798 virtual void record_stop_world_start(); | |
799 | |
800 virtual void record_collection_pause_start(double start_time_sec, | |
801 size_t start_used); | |
802 | |
803 // Must currently be called while the world is stopped. | |
804 virtual void record_concurrent_mark_init_start(); | |
805 virtual void record_concurrent_mark_init_end(); | |
806 void record_concurrent_mark_init_end_pre(double | |
807 mark_init_elapsed_time_ms); | |
808 | |
809 void record_mark_closure_time(double mark_closure_time_ms); | |
810 | |
811 virtual void record_concurrent_mark_remark_start(); | |
812 virtual void record_concurrent_mark_remark_end(); | |
813 | |
814 virtual void record_concurrent_mark_cleanup_start(); | |
815 virtual void record_concurrent_mark_cleanup_end(size_t freed_bytes, | |
816 size_t max_live_bytes); | |
817 virtual void record_concurrent_mark_cleanup_completed(); | |
818 | |
819 virtual void record_concurrent_pause(); | |
820 virtual void record_concurrent_pause_end(); | |
821 | |
822 virtual void record_collection_pause_end_CH_strong_roots(); | |
823 virtual void record_collection_pause_end_G1_strong_roots(); | |
824 | |
677 | 825 virtual void record_collection_pause_end(bool abandoned); |
342 | 826 |
827 // Record the fact that a full collection occurred. | |
828 virtual void record_full_collection_start(); | |
829 virtual void record_full_collection_end(); | |
830 | |
831 void record_ext_root_scan_time(int worker_i, double ms) { | |
832 _par_last_ext_root_scan_times_ms[worker_i] = ms; | |
833 } | |
834 | |
835 void record_mark_stack_scan_time(int worker_i, double ms) { | |
836 _par_last_mark_stack_scan_times_ms[worker_i] = ms; | |
837 } | |
838 | |
839 void record_scan_only_time(int worker_i, double ms, int n) { | |
840 _par_last_scan_only_times_ms[worker_i] = ms; | |
841 _par_last_scan_only_regions_scanned[worker_i] = (double) n; | |
842 } | |
843 | |
844 void record_satb_drain_time(double ms) { | |
845 _cur_satb_drain_time_ms = ms; | |
846 _satb_drain_time_set = true; | |
847 } | |
848 | |
849 void record_satb_drain_processed_buffers (int processed_buffers) { | |
850 _last_satb_drain_processed_buffers = processed_buffers; | |
851 } | |
852 | |
853 void record_mod_union_time(double ms) { | |
854 _all_mod_union_times_ms->add(ms); | |
855 } | |
856 | |
857 void record_update_rs_start_time(int thread, double ms) { | |
858 _par_last_update_rs_start_times_ms[thread] = ms; | |
859 } | |
860 | |
861 void record_update_rs_time(int thread, double ms) { | |
862 _par_last_update_rs_times_ms[thread] = ms; | |
863 } | |
864 | |
865 void record_update_rs_processed_buffers (int thread, | |
866 double processed_buffers) { | |
867 _par_last_update_rs_processed_buffers[thread] = processed_buffers; | |
868 } | |
869 | |
870 void record_scan_rs_start_time(int thread, double ms) { | |
871 _par_last_scan_rs_start_times_ms[thread] = ms; | |
872 } | |
873 | |
874 void record_scan_rs_time(int thread, double ms) { | |
875 _par_last_scan_rs_times_ms[thread] = ms; | |
876 } | |
877 | |
878 void record_scan_new_refs_time(int thread, double ms) { | |
879 _par_last_scan_new_refs_times_ms[thread] = ms; | |
880 } | |
881 | |
882 double get_scan_new_refs_time(int thread) { | |
883 return _par_last_scan_new_refs_times_ms[thread]; | |
884 } | |
885 | |
886 void reset_obj_copy_time(int thread) { | |
887 _par_last_obj_copy_times_ms[thread] = 0.0; | |
888 } | |
889 | |
890 void reset_obj_copy_time() { | |
891 reset_obj_copy_time(0); | |
892 } | |
893 | |
894 void record_obj_copy_time(int thread, double ms) { | |
895 _par_last_obj_copy_times_ms[thread] += ms; | |
896 } | |
897 | |
898 void record_obj_copy_time(double ms) { | |
899 record_obj_copy_time(0, ms); | |
900 } | |
901 | |
902 void record_termination_time(int thread, double ms) { | |
903 _par_last_termination_times_ms[thread] = ms; | |
904 } | |
905 | |
906 void record_termination_time(double ms) { | |
907 record_termination_time(0, ms); | |
908 } | |
909 | |
595
3698e8f47799
6804746: G1: guarantee(variance() > -1.0,"variance should be >= 0") (due to evacuation failure)
tonyp
parents:
549
diff
changeset
|
910 void record_pause_time_ms(double ms) { |
342 | 911 _last_pause_time_ms = ms; |
912 } | |
913 | |
914 void record_clear_ct_time(double ms) { | |
915 _cur_clear_ct_time_ms = ms; | |
916 } | |
917 | |
918 void record_par_time(double ms) { | |
919 _cur_collection_par_time_ms = ms; | |
920 } | |
921 | |
922 void record_aux_start_time(int i) { | |
923 guarantee(i < _aux_num, "should be within range"); | |
924 _cur_aux_start_times_ms[i] = os::elapsedTime() * 1000.0; | |
925 } | |
926 | |
927 void record_aux_end_time(int i) { | |
928 guarantee(i < _aux_num, "should be within range"); | |
929 double ms = os::elapsedTime() * 1000.0 - _cur_aux_start_times_ms[i]; | |
930 _cur_aux_times_set[i] = true; | |
931 _cur_aux_times_ms[i] += ms; | |
932 } | |
933 | |
934 // Record the fact that "bytes" bytes allocated in a region. | |
935 void record_before_bytes(size_t bytes); | |
936 void record_after_bytes(size_t bytes); | |
937 | |
938 // Returns "true" if this is a good time to do a collection pause. | |
939 // The "word_size" argument, if non-zero, indicates the size of an | |
940 // allocation request that is prompting this query. | |
941 virtual bool should_do_collection_pause(size_t word_size) = 0; | |
942 | |
943 // Choose a new collection set. Marks the chosen regions as being | |
944 // "in_collection_set", and links them together. The head and number of | |
945 // the collection set are available via access methods. | |
677 | 946 virtual void choose_collection_set() = 0; |
342 | 947 |
948 void clear_collection_set() { _collection_set = NULL; } | |
949 | |
950 // The head of the list (via "next_in_collection_set()") representing the | |
951 // current collection set. | |
952 HeapRegion* collection_set() { return _collection_set; } | |
953 | |
954 // The number of elements in the current collection set. | |
955 size_t collection_set_size() { return _collection_set_size; } | |
956 | |
957 // Add "hr" to the CS. | |
958 void add_to_collection_set(HeapRegion* hr); | |
959 | |
960 bool should_initiate_conc_mark() { return _should_initiate_conc_mark; } | |
961 void set_should_initiate_conc_mark() { _should_initiate_conc_mark = true; } | |
962 void unset_should_initiate_conc_mark(){ _should_initiate_conc_mark = false; } | |
963 | |
964 void checkpoint_conc_overhead(); | |
965 | |
966 // If an expansion would be appropriate, because recent GC overhead had | |
967 // exceeded the desired limit, return an amount to expand by. | |
968 virtual size_t expansion_amount(); | |
969 | |
970 // note start of mark thread | |
971 void note_start_of_mark_thread(); | |
972 | |
973 // The marked bytes of the "r" has changed; reclassify it's desirability | |
974 // for marking. Also asserts that "r" is eligible for a CS. | |
975 virtual void note_change_in_marked_bytes(HeapRegion* r) = 0; | |
976 | |
977 #ifndef PRODUCT | |
978 // Check any appropriate marked bytes info, asserting false if | |
979 // something's wrong, else returning "true". | |
980 virtual bool assertMarkedBytesDataOK() = 0; | |
981 #endif | |
982 | |
983 // Print tracing information. | |
984 void print_tracing_info() const; | |
985 | |
986 // Print stats on young survival ratio | |
987 void print_yg_surv_rate_info() const; | |
988 | |
545 | 989 void finished_recalculating_age_indexes(bool is_survivors) { |
990 if (is_survivors) { | |
991 _survivor_surv_rate_group->finished_recalculating_age_indexes(); | |
992 } else { | |
993 _short_lived_surv_rate_group->finished_recalculating_age_indexes(); | |
994 } | |
342 | 995 // do that for any other surv rate groups |
996 } | |
997 | |
998 bool should_add_next_region_to_young_list(); | |
999 | |
1000 bool in_young_gc_mode() { | |
1001 return _in_young_gc_mode; | |
1002 } | |
1003 void set_in_young_gc_mode(bool in_young_gc_mode) { | |
1004 _in_young_gc_mode = in_young_gc_mode; | |
1005 } | |
1006 | |
1007 bool full_young_gcs() { | |
1008 return _full_young_gcs; | |
1009 } | |
1010 void set_full_young_gcs(bool full_young_gcs) { | |
1011 _full_young_gcs = full_young_gcs; | |
1012 } | |
1013 | |
1014 bool adaptive_young_list_length() { | |
1015 return _adaptive_young_list_length; | |
1016 } | |
1017 void set_adaptive_young_list_length(bool adaptive_young_list_length) { | |
1018 _adaptive_young_list_length = adaptive_young_list_length; | |
1019 } | |
1020 | |
1021 inline double get_gc_eff_factor() { | |
1022 double ratio = _known_garbage_ratio; | |
1023 | |
1024 double square = ratio * ratio; | |
1025 // square = square * square; | |
1026 double ret = square * 9.0 + 1.0; | |
1027 #if 0 | |
1028 gclog_or_tty->print_cr("ratio = %1.2lf, ret = %1.2lf", ratio, ret); | |
1029 #endif // 0 | |
1030 guarantee(0.0 <= ret && ret < 10.0, "invariant!"); | |
1031 return ret; | |
1032 } | |
1033 | |
1034 // | |
1035 // Survivor regions policy. | |
1036 // | |
1037 protected: | |
1038 | |
1039 // Current tenuring threshold, set to 0 if the collector reaches the | |
1040 // maximum amount of suvivors regions. | |
1041 int _tenuring_threshold; | |
1042 | |
545 | 1043 // The limit on the number of regions allocated for survivors. |
1044 size_t _max_survivor_regions; | |
1045 | |
1046 // The amount of survor regions after a collection. | |
1047 size_t _recorded_survivor_regions; | |
1048 // List of survivor regions. | |
1049 HeapRegion* _recorded_survivor_head; | |
1050 HeapRegion* _recorded_survivor_tail; | |
1051 | |
1052 ageTable _survivors_age_table; | |
1053 | |
342 | 1054 public: |
1055 | |
1056 inline GCAllocPurpose | |
1057 evacuation_destination(HeapRegion* src_region, int age, size_t word_sz) { | |
1058 if (age < _tenuring_threshold && src_region->is_young()) { | |
1059 return GCAllocForSurvived; | |
1060 } else { | |
1061 return GCAllocForTenured; | |
1062 } | |
1063 } | |
1064 | |
1065 inline bool track_object_age(GCAllocPurpose purpose) { | |
1066 return purpose == GCAllocForSurvived; | |
1067 } | |
1068 | |
1069 inline GCAllocPurpose alternative_purpose(int purpose) { | |
1070 return GCAllocForTenured; | |
1071 } | |
1072 | |
545 | 1073 static const size_t REGIONS_UNLIMITED = ~(size_t)0; |
1074 | |
1075 size_t max_regions(int purpose); | |
342 | 1076 |
1077 // The limit on regions for a particular purpose is reached. | |
1078 void note_alloc_region_limit_reached(int purpose) { | |
1079 if (purpose == GCAllocForSurvived) { | |
1080 _tenuring_threshold = 0; | |
1081 } | |
1082 } | |
1083 | |
1084 void note_start_adding_survivor_regions() { | |
1085 _survivor_surv_rate_group->start_adding_regions(); | |
1086 } | |
1087 | |
1088 void note_stop_adding_survivor_regions() { | |
1089 _survivor_surv_rate_group->stop_adding_regions(); | |
1090 } | |
545 | 1091 |
1092 void record_survivor_regions(size_t regions, | |
1093 HeapRegion* head, | |
1094 HeapRegion* tail) { | |
1095 _recorded_survivor_regions = regions; | |
1096 _recorded_survivor_head = head; | |
1097 _recorded_survivor_tail = tail; | |
1098 } | |
1099 | |
1100 void record_thread_age_table(ageTable* age_table) | |
1101 { | |
1102 _survivors_age_table.merge_par(age_table); | |
1103 } | |
1104 | |
1105 // Calculates survivor space parameters. | |
1106 void calculate_survivors_policy(); | |
1107 | |
342 | 1108 }; |
1109 | |
1110 // This encapsulates a particular strategy for a g1 Collector. | |
1111 // | |
1112 // Start a concurrent mark when our heap size is n bytes | |
1113 // greater then our heap size was at the last concurrent | |
1114 // mark. Where n is a function of the CMSTriggerRatio | |
1115 // and the MinHeapFreeRatio. | |
1116 // | |
1117 // Start a g1 collection pause when we have allocated the | |
1118 // average number of bytes currently being freed in | |
1119 // a collection, but only if it is at least one region | |
1120 // full | |
1121 // | |
1122 // Resize Heap based on desired | |
1123 // allocation space, where desired allocation space is | |
1124 // a function of survival rate and desired future to size. | |
1125 // | |
1126 // Choose collection set by first picking all older regions | |
1127 // which have a survival rate which beats our projected young | |
1128 // survival rate. Then fill out the number of needed regions | |
1129 // with young regions. | |
1130 | |
1131 class G1CollectorPolicy_BestRegionsFirst: public G1CollectorPolicy { | |
1132 CollectionSetChooser* _collectionSetChooser; | |
1133 // If the estimated is less then desirable, resize if possible. | |
1134 void expand_if_possible(size_t numRegions); | |
1135 | |
677 | 1136 virtual void choose_collection_set(); |
342 | 1137 virtual void record_collection_pause_start(double start_time_sec, |
1138 size_t start_used); | |
1139 virtual void record_concurrent_mark_cleanup_end(size_t freed_bytes, | |
1140 size_t max_live_bytes); | |
1141 virtual void record_full_collection_end(); | |
1142 | |
1143 public: | |
1144 G1CollectorPolicy_BestRegionsFirst() { | |
1145 _collectionSetChooser = new CollectionSetChooser(); | |
1146 } | |
677 | 1147 void record_collection_pause_end(bool abandoned); |
342 | 1148 bool should_do_collection_pause(size_t word_size); |
1149 // This is not needed any more, after the CSet choosing code was | |
1150 // changed to use the pause prediction work. But let's leave the | |
1151 // hook in just in case. | |
1152 void note_change_in_marked_bytes(HeapRegion* r) { } | |
1153 #ifndef PRODUCT | |
1154 bool assertMarkedBytesDataOK(); | |
1155 #endif | |
1156 }; | |
1157 | |
1158 // This should move to some place more general... | |
1159 | |
1160 // If we have "n" measurements, and we've kept track of their "sum" and the | |
1161 // "sum_of_squares" of the measurements, this returns the variance of the | |
1162 // sequence. | |
1163 inline double variance(int n, double sum_of_squares, double sum) { | |
1164 double n_d = (double)n; | |
1165 double avg = sum/n_d; | |
1166 return (sum_of_squares - 2.0 * avg * sum + n_d * avg * avg) / n_d; | |
1167 } | |
1168 | |
1169 // Local Variables: *** | |
1170 // c-indentation-style: gnu *** | |
1171 // End: *** |