Thu, 20 Sep 2012 09:52:56 -0700
7190666: G1: assert(_unused == 0) failed: Inconsistency in PLAB stats
Summary: Reset the fields in ParGCAllocBuffer, that are used for accumulating values for the ResizePLAB sensors in PLABStats, to zero after flushing the values to the PLABStats fields. Flush PLABStats values only when retiring the final allocation buffers prior to disposing of a G1ParScanThreadState object, rather than when retiring every allocation buffer.
Reviewed-by: jwilhelm, jmasa, ysr
1 /*
2 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
25 #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_ALLOCATIONSTATS_HPP
26 #define SHARE_VM_GC_IMPLEMENTATION_SHARED_ALLOCATIONSTATS_HPP
28 #ifndef SERIALGC
29 #include "gc_implementation/shared/gcUtil.hpp"
30 #include "memory/allocation.hpp"
31 #include "utilities/globalDefinitions.hpp"
32 #endif
34 class AllocationStats VALUE_OBJ_CLASS_SPEC {
35 // A duration threshold (in ms) used to filter
36 // possibly unreliable samples.
37 static float _threshold;
39 // We measure the demand between the end of the previous sweep and
40 // beginning of this sweep:
41 // Count(end_last_sweep) - Count(start_this_sweep)
42 // + split_births(between) - split_deaths(between)
43 // The above number divided by the time since the end of the
44 // previous sweep gives us a time rate of demand for blocks
45 // of this size. We compute a padded average of this rate as
46 // our current estimate for the time rate of demand for blocks
47 // of this size. Similarly, we keep a padded average for the time
48 // between sweeps. Our current estimate for demand for blocks of
49 // this size is then simply computed as the product of these two
50 // estimates.
51 AdaptivePaddedAverage _demand_rate_estimate;
53 ssize_t _desired; // Demand stimate computed as described above
54 ssize_t _coal_desired; // desired +/- small-percent for tuning coalescing
56 ssize_t _surplus; // count - (desired +/- small-percent),
57 // used to tune splitting in best fit
58 ssize_t _bfr_surp; // surplus at start of current sweep
59 ssize_t _prev_sweep; // count from end of previous sweep
60 ssize_t _before_sweep; // count from before current sweep
61 ssize_t _coal_births; // additional chunks from coalescing
62 ssize_t _coal_deaths; // loss from coalescing
63 ssize_t _split_births; // additional chunks from splitting
64 ssize_t _split_deaths; // loss from splitting
65 size_t _returned_bytes; // number of bytes returned to list.
66 public:
67 void initialize(bool split_birth = false) {
68 AdaptivePaddedAverage* dummy =
69 new (&_demand_rate_estimate) AdaptivePaddedAverage(CMS_FLSWeight,
70 CMS_FLSPadding);
71 _desired = 0;
72 _coal_desired = 0;
73 _surplus = 0;
74 _bfr_surp = 0;
75 _prev_sweep = 0;
76 _before_sweep = 0;
77 _coal_births = 0;
78 _coal_deaths = 0;
79 _split_births = (split_birth ? 1 : 0);
80 _split_deaths = 0;
81 _returned_bytes = 0;
82 }
84 AllocationStats() {
85 initialize();
86 }
88 // The rate estimate is in blocks per second.
89 void compute_desired(size_t count,
90 float inter_sweep_current,
91 float inter_sweep_estimate,
92 float intra_sweep_estimate) {
93 // If the latest inter-sweep time is below our granularity
94 // of measurement, we may call in here with
95 // inter_sweep_current == 0. However, even for suitably small
96 // but non-zero inter-sweep durations, we may not trust the accuracy
97 // of accumulated data, since it has not been "integrated"
98 // (read "low-pass-filtered") long enough, and would be
99 // vulnerable to noisy glitches. In such cases, we
100 // ignore the current sample and use currently available
101 // historical estimates.
102 assert(prev_sweep() + split_births() + coal_births() // "Total Production Stock"
103 >= split_deaths() + coal_deaths() + (ssize_t)count, // "Current stock + depletion"
104 "Conservation Principle");
105 if (inter_sweep_current > _threshold) {
106 ssize_t demand = prev_sweep() - (ssize_t)count + split_births() + coal_births()
107 - split_deaths() - coal_deaths();
108 assert(demand >= 0,
109 err_msg("Demand (" SSIZE_FORMAT ") should be non-negative for "
110 PTR_FORMAT " (size=" SIZE_FORMAT ")",
111 demand, this, count));
112 // Defensive: adjust for imprecision in event counting
113 if (demand < 0) {
114 demand = 0;
115 }
116 float old_rate = _demand_rate_estimate.padded_average();
117 float rate = ((float)demand)/inter_sweep_current;
118 _demand_rate_estimate.sample(rate);
119 float new_rate = _demand_rate_estimate.padded_average();
120 ssize_t old_desired = _desired;
121 float delta_ise = (CMSExtrapolateSweep ? intra_sweep_estimate : 0.0);
122 _desired = (ssize_t)(new_rate * (inter_sweep_estimate + delta_ise));
123 if (PrintFLSStatistics > 1) {
124 gclog_or_tty->print_cr("demand: %d, old_rate: %f, current_rate: %f, new_rate: %f, old_desired: %d, new_desired: %d",
125 demand, old_rate, rate, new_rate, old_desired, _desired);
126 }
127 }
128 }
130 ssize_t desired() const { return _desired; }
131 void set_desired(ssize_t v) { _desired = v; }
133 ssize_t coal_desired() const { return _coal_desired; }
134 void set_coal_desired(ssize_t v) { _coal_desired = v; }
136 ssize_t surplus() const { return _surplus; }
137 void set_surplus(ssize_t v) { _surplus = v; }
138 void increment_surplus() { _surplus++; }
139 void decrement_surplus() { _surplus--; }
141 ssize_t bfr_surp() const { return _bfr_surp; }
142 void set_bfr_surp(ssize_t v) { _bfr_surp = v; }
143 ssize_t prev_sweep() const { return _prev_sweep; }
144 void set_prev_sweep(ssize_t v) { _prev_sweep = v; }
145 ssize_t before_sweep() const { return _before_sweep; }
146 void set_before_sweep(ssize_t v) { _before_sweep = v; }
148 ssize_t coal_births() const { return _coal_births; }
149 void set_coal_births(ssize_t v) { _coal_births = v; }
150 void increment_coal_births() { _coal_births++; }
152 ssize_t coal_deaths() const { return _coal_deaths; }
153 void set_coal_deaths(ssize_t v) { _coal_deaths = v; }
154 void increment_coal_deaths() { _coal_deaths++; }
156 ssize_t split_births() const { return _split_births; }
157 void set_split_births(ssize_t v) { _split_births = v; }
158 void increment_split_births() { _split_births++; }
160 ssize_t split_deaths() const { return _split_deaths; }
161 void set_split_deaths(ssize_t v) { _split_deaths = v; }
162 void increment_split_deaths() { _split_deaths++; }
164 NOT_PRODUCT(
165 size_t returned_bytes() const { return _returned_bytes; }
166 void set_returned_bytes(size_t v) { _returned_bytes = v; }
167 )
168 };
170 #endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_ALLOCATIONSTATS_HPP