Mercurial > hg > truffle
annotate src/share/vm/services/memTrackWorker.cpp @ 6599:4acebbe310e1
7185614: NMT ON: "check by caller" assertion failed on nsk ThreadMXBean test
7187429: NMT ON: Merge failure should cause NMT to shutdown
Summary: Fixed NMT assertion failures
Reviewed-by: acorn, kvn
author | zgu |
---|---|
date | Wed, 01 Aug 2012 17:19:30 -0400 |
parents | d2a62e0f25eb |
children | 33143ee07800 |
rev | line source |
---|---|
6197 | 1 /* |
2 * Copyright (c) 2012, 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 */ | |
24 | |
25 #include "precompiled.hpp" | |
26 #include "runtime/threadCritical.hpp" | |
27 #include "services/memTracker.hpp" | |
28 #include "services/memTrackWorker.hpp" | |
29 #include "utilities/decoder.hpp" | |
30 #include "utilities/vmError.hpp" | |
31 | |
32 MemTrackWorker::MemTrackWorker() { | |
33 // create thread uses cgc thread type for now. We should revisit | |
34 // the option, or create new thread type. | |
35 _has_error = !os::create_thread(this, os::cgc_thread); | |
36 set_name("MemTrackWorker", 0); | |
37 | |
38 // initial generation circuit buffer | |
39 if (!has_error()) { | |
40 _head = _tail = 0; | |
41 for(int index = 0; index < MAX_GENERATIONS; index ++) { | |
42 _gen[index] = NULL; | |
43 } | |
44 } | |
45 NOT_PRODUCT(_sync_point_count = 0;) | |
46 NOT_PRODUCT(_merge_count = 0;) | |
47 NOT_PRODUCT(_last_gen_in_use = 0;) | |
48 } | |
49 | |
50 MemTrackWorker::~MemTrackWorker() { | |
51 for (int index = 0; index < MAX_GENERATIONS; index ++) { | |
52 MemRecorder* rc = _gen[index]; | |
53 if (rc != NULL) { | |
54 delete rc; | |
55 } | |
56 } | |
57 } | |
58 | |
59 void* MemTrackWorker::operator new(size_t size) { | |
60 assert(false, "use nothrow version"); | |
61 return NULL; | |
62 } | |
63 | |
64 void* MemTrackWorker::operator new(size_t size, const std::nothrow_t& nothrow_constant) { | |
65 return allocate(size, false, mtNMT); | |
66 } | |
67 | |
68 void MemTrackWorker::start() { | |
69 os::start_thread(this); | |
70 } | |
71 | |
72 /* | |
73 * Native memory tracking worker thread loop: | |
74 * 1. merge one generation of memory recorders to staging area | |
75 * 2. promote staging data to memory snapshot | |
76 * | |
77 * This thread can run through safepoint. | |
78 */ | |
79 | |
80 void MemTrackWorker::run() { | |
81 assert(MemTracker::is_on(), "native memory tracking is off"); | |
82 this->initialize_thread_local_storage(); | |
83 this->record_stack_base_and_size(); | |
84 MemSnapshot* snapshot = MemTracker::get_snapshot(); | |
85 assert(snapshot != NULL, "Worker should not be started"); | |
86 MemRecorder* rec; | |
87 | |
88 while (!MemTracker::shutdown_in_progress()) { | |
89 NOT_PRODUCT(_last_gen_in_use = generations_in_use();) | |
90 { | |
91 // take a recorder from earliest generation in buffer | |
92 ThreadCritical tc; | |
93 rec = _gen[_head]; | |
94 if (rec != NULL) { | |
95 _gen[_head] = rec->next(); | |
96 } | |
97 assert(count_recorder(_gen[_head]) <= MemRecorder::_instance_count, | |
98 "infinite loop after dequeue"); | |
99 } | |
100 if (rec != NULL) { | |
101 // merge the recorder into staging area | |
6599
4acebbe310e1
7185614: NMT ON: "check by caller" assertion failed on nsk ThreadMXBean test
zgu
parents:
6197
diff
changeset
|
102 if (!snapshot->merge(rec)) { |
4acebbe310e1
7185614: NMT ON: "check by caller" assertion failed on nsk ThreadMXBean test
zgu
parents:
6197
diff
changeset
|
103 MemTracker::shutdown(MemTracker::NMT_out_of_memory); |
4acebbe310e1
7185614: NMT ON: "check by caller" assertion failed on nsk ThreadMXBean test
zgu
parents:
6197
diff
changeset
|
104 } else { |
4acebbe310e1
7185614: NMT ON: "check by caller" assertion failed on nsk ThreadMXBean test
zgu
parents:
6197
diff
changeset
|
105 NOT_PRODUCT(_merge_count ++;) |
4acebbe310e1
7185614: NMT ON: "check by caller" assertion failed on nsk ThreadMXBean test
zgu
parents:
6197
diff
changeset
|
106 } |
6197 | 107 MemTracker::release_thread_recorder(rec); |
108 } else { | |
109 // no more recorder to merge, promote staging area | |
110 // to snapshot | |
111 if (_head != _tail) { | |
112 { | |
113 ThreadCritical tc; | |
114 if (_gen[_head] != NULL || _head == _tail) { | |
115 continue; | |
116 } | |
117 // done with this generation, increment _head pointer | |
118 _head = (_head + 1) % MAX_GENERATIONS; | |
119 } | |
120 // promote this generation data to snapshot | |
121 snapshot->promote(); | |
122 } else { | |
123 snapshot->wait(1000); | |
124 ThreadCritical tc; | |
125 // check if more data arrived | |
126 if (_gen[_head] == NULL) { | |
127 _gen[_head] = MemTracker::get_pending_recorders(); | |
128 } | |
129 } | |
130 } | |
131 } | |
132 assert(MemTracker::shutdown_in_progress(), "just check"); | |
133 | |
6599
4acebbe310e1
7185614: NMT ON: "check by caller" assertion failed on nsk ThreadMXBean test
zgu
parents:
6197
diff
changeset
|
134 // transits to final shutdown |
6197 | 135 MemTracker::final_shutdown(); |
136 } | |
137 | |
138 // at synchronization point, where 'safepoint visible' Java threads are blocked | |
139 // at a safepoint, and the rest of threads are blocked on ThreadCritical lock. | |
140 // The caller MemTracker::sync() already takes ThreadCritical before calling this | |
141 // method. | |
142 // | |
143 // Following tasks are performed: | |
144 // 1. add all recorders in pending queue to current generation | |
145 // 2. increase generation | |
146 | |
147 void MemTrackWorker::at_sync_point(MemRecorder* rec) { | |
148 NOT_PRODUCT(_sync_point_count ++;) | |
149 assert(count_recorder(rec) <= MemRecorder::_instance_count, | |
150 "pending queue has infinite loop"); | |
151 | |
152 bool out_of_generation_buffer = false; | |
153 // check shutdown state inside ThreadCritical | |
154 if (MemTracker::shutdown_in_progress()) return; | |
155 // append the recorders to the end of the generation | |
156 if( rec != NULL) { | |
157 MemRecorder* cur_head = _gen[_tail]; | |
158 if (cur_head == NULL) { | |
159 _gen[_tail] = rec; | |
160 } else { | |
161 while (cur_head->next() != NULL) { | |
162 cur_head = cur_head->next(); | |
163 } | |
164 cur_head->set_next(rec); | |
165 } | |
166 } | |
167 assert(count_recorder(rec) <= MemRecorder::_instance_count, | |
168 "after add to current generation has infinite loop"); | |
169 // we have collected all recorders for this generation. If there is data, | |
170 // we need to increment _tail to start a new generation. | |
171 if (_gen[_tail] != NULL || _head == _tail) { | |
172 _tail = (_tail + 1) % MAX_GENERATIONS; | |
173 out_of_generation_buffer = (_tail == _head); | |
174 } | |
175 | |
176 if (out_of_generation_buffer) { | |
177 MemTracker::shutdown(MemTracker::NMT_out_of_generation); | |
178 } | |
179 } | |
180 | |
181 #ifndef PRODUCT | |
182 int MemTrackWorker::count_recorder(const MemRecorder* head) { | |
183 int count = 0; | |
184 while(head != NULL) { | |
185 count ++; | |
186 head = head->next(); | |
187 } | |
188 return count; | |
189 } | |
190 | |
191 int MemTrackWorker::count_pending_recorders() const { | |
192 int count = 0; | |
193 for (int index = 0; index < MAX_GENERATIONS; index ++) { | |
194 MemRecorder* head = _gen[index]; | |
195 if (head != NULL) { | |
196 count += count_recorder(head); | |
197 } | |
198 } | |
199 return count; | |
200 } | |
201 #endif |