Thu, 20 Nov 2008 16:56:09 -0800
6684579: SoftReference processing can be made more efficient
Summary: For current soft-ref clearing policies, we can decide at marking time if a soft-reference will definitely not be cleared, postponing the decision of whether it will definitely be cleared to the final reference processing phase. This can be especially beneficial in the case of concurrent collectors where the marking is usually concurrent but reference processing is usually not.
Reviewed-by: jmasa
1 /*
2 * Copyright 2001-2006 Sun Microsystems, Inc. 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 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 */
25 class ConcurrentMarkSweepGeneration;
26 class CMSCollector;
28 // The Concurrent Mark Sweep GC Thread (could be several in the future).
29 class ConcurrentMarkSweepThread: public ConcurrentGCThread {
30 friend class VMStructs;
31 friend class ConcurrentMarkSweepGeneration; // XXX should remove friendship
32 friend class CMSCollector;
33 public:
34 virtual void run();
36 private:
37 static ConcurrentMarkSweepThread* _cmst;
38 static CMSCollector* _collector;
39 static SurrogateLockerThread* _slt;
40 static SurrogateLockerThread::SLT_msg_type _sltBuffer;
41 static Monitor* _sltMonitor;
43 ConcurrentMarkSweepThread* _next;
45 static bool _should_terminate;
47 enum CMS_flag_type {
48 CMS_nil = NoBits,
49 CMS_cms_wants_token = nth_bit(0),
50 CMS_cms_has_token = nth_bit(1),
51 CMS_vm_wants_token = nth_bit(2),
52 CMS_vm_has_token = nth_bit(3)
53 };
55 static int _CMS_flag;
57 static bool CMS_flag_is_set(int b) { return (_CMS_flag & b) != 0; }
58 static bool set_CMS_flag(int b) { return (_CMS_flag |= b) != 0; }
59 static bool clear_CMS_flag(int b) { return (_CMS_flag &= ~b) != 0; }
60 void sleepBeforeNextCycle();
62 // CMS thread should yield for a young gen collection, direct allocation,
63 // and iCMS activity.
64 static char _pad_1[64 - sizeof(jint)]; // prevent cache-line sharing
65 static volatile jint _pending_yields;
66 static volatile jint _pending_decrements; // decrements to _pending_yields
67 static char _pad_2[64 - sizeof(jint)]; // prevent cache-line sharing
69 // Tracing messages, enabled by CMSTraceThreadState.
70 static inline void trace_state(const char* desc);
72 static volatile bool _icms_enabled; // iCMS enabled?
73 static volatile bool _should_run; // iCMS may run
74 static volatile bool _should_stop; // iCMS should stop
76 // debugging
77 void verify_ok_to_terminate() const PRODUCT_RETURN;
79 public:
80 // Constructor
81 ConcurrentMarkSweepThread(CMSCollector* collector);
83 static void makeSurrogateLockerThread(TRAPS);
84 static SurrogateLockerThread* slt() { return _slt; }
86 // Tester
87 bool is_ConcurrentGC_thread() const { return true; }
89 static void threads_do(ThreadClosure* tc);
91 // Printing
92 void print_on(outputStream* st) const;
93 void print() const { print_on(tty); }
94 static void print_all_on(outputStream* st);
95 static void print_all() { print_all_on(tty); }
97 // Returns the CMS Thread
98 static ConcurrentMarkSweepThread* cmst() { return _cmst; }
99 static CMSCollector* collector() { return _collector; }
101 // Create and start the CMS Thread, or stop it on shutdown
102 static ConcurrentMarkSweepThread* start(CMSCollector* collector);
103 static void stop();
104 static bool should_terminate() { return _should_terminate; }
106 // Synchronization using CMS token
107 static void synchronize(bool is_cms_thread);
108 static void desynchronize(bool is_cms_thread);
109 static bool vm_thread_has_cms_token() {
110 return CMS_flag_is_set(CMS_vm_has_token);
111 }
112 static bool cms_thread_has_cms_token() {
113 return CMS_flag_is_set(CMS_cms_has_token);
114 }
115 static bool vm_thread_wants_cms_token() {
116 return CMS_flag_is_set(CMS_vm_wants_token);
117 }
118 static bool cms_thread_wants_cms_token() {
119 return CMS_flag_is_set(CMS_cms_wants_token);
120 }
122 // Wait on CMS lock until the next synchronous GC
123 // or given timeout, whichever is earlier.
124 void wait_on_cms_lock(long t); // milliseconds
126 // The CMS thread will yield during the work portion of it's cycle
127 // only when requested to. Both synchronous and asychronous requests
128 // are provided. A synchronous request is used for young gen
129 // collections and direct allocations. The requesting thread increments
130 // pending_yields at the beginning of an operation, and decrements it when
131 // the operation is completed. The CMS thread yields when pending_yields
132 // is positive. An asynchronous request is used by iCMS in the stop_icms()
133 // operation. A single yield satisfies the outstanding asynch yield requests.
134 // The requesting thread increments both pending_yields and pending_decrements.
135 // After yielding, the CMS thread decrements both by the amount in
136 // pending_decrements.
137 // Note that, while "_pending_yields >= _pending_decrements" is an invariant,
138 // we cannot easily test that invariant, since the counters are manipulated via
139 // atomic instructions without explicit locking and we cannot read
140 // the two counters atomically together: one suggestion is to
141 // use (for example) 16-bit counters so as to be able to read the
142 // two counters atomically even on 32-bit platforms. Notice that
143 // the second assert in acknowledge_yield_request() does indeed
144 // check a form of the above invariant, albeit indirectly.
146 static void increment_pending_yields() {
147 Atomic::inc(&_pending_yields);
148 assert(_pending_yields >= 0, "can't be negative");
149 }
150 static void decrement_pending_yields() {
151 Atomic::dec(&_pending_yields);
152 assert(_pending_yields >= 0, "can't be negative");
153 }
154 static void asynchronous_yield_request() {
155 increment_pending_yields();
156 Atomic::inc(&_pending_decrements);
157 assert(_pending_decrements >= 0, "can't be negative");
158 }
159 static void acknowledge_yield_request() {
160 jint decrement = _pending_decrements;
161 if (decrement > 0) {
162 // Order important to preserve: _pending_yields >= _pending_decrements
163 Atomic::add(-decrement, &_pending_decrements);
164 Atomic::add(-decrement, &_pending_yields);
165 assert(_pending_decrements >= 0, "can't be negative");
166 assert(_pending_yields >= 0, "can't be negative");
167 }
168 }
169 static bool should_yield() { return _pending_yields > 0; }
171 // CMS incremental mode.
172 static void start_icms(); // notify thread to start a quantum of work
173 static void stop_icms(); // request thread to stop working
174 void icms_wait(); // if asked to stop, wait until notified to start
176 // Incremental mode is enabled globally by the flag CMSIncrementalMode. It
177 // must also be enabled/disabled dynamically to allow foreground collections.
178 static inline void enable_icms() { _icms_enabled = true; }
179 static inline void disable_icms() { _icms_enabled = false; }
180 static inline void set_icms_enabled(bool val) { _icms_enabled = val; }
181 static inline bool icms_enabled() { return _icms_enabled; }
182 };
184 inline void ConcurrentMarkSweepThread::trace_state(const char* desc) {
185 if (CMSTraceThreadState) {
186 char buf[128];
187 TimeStamp& ts = gclog_or_tty->time_stamp();
188 if (!ts.is_updated()) {
189 ts.update();
190 }
191 jio_snprintf(buf, sizeof(buf), " [%.3f: CMSThread %s] ",
192 ts.seconds(), desc);
193 buf[sizeof(buf) - 1] = '\0';
194 gclog_or_tty->print(buf);
195 }
196 }
198 // For scoped increment/decrement of yield requests
199 class CMSSynchronousYieldRequest: public StackObj {
200 public:
201 CMSSynchronousYieldRequest() {
202 ConcurrentMarkSweepThread::increment_pending_yields();
203 }
204 ~CMSSynchronousYieldRequest() {
205 ConcurrentMarkSweepThread::decrement_pending_yields();
206 }
207 };
209 // Used to emit a warning in case of unexpectedly excessive
210 // looping (in "apparently endless loops") in CMS code.
211 class CMSLoopCountWarn: public StackObj {
212 private:
213 const char* _src;
214 const char* _msg;
215 const intx _threshold;
216 intx _ticks;
218 public:
219 inline CMSLoopCountWarn(const char* src, const char* msg,
220 const intx threshold) :
221 _src(src), _msg(msg), _threshold(threshold), _ticks(0) { }
223 inline void tick() {
224 _ticks++;
225 if (CMSLoopWarn && _ticks % _threshold == 0) {
226 warning("%s has looped %d times %s", _src, _ticks, _msg);
227 }
228 }
229 };