Mercurial > hg > graal-compiler
comparison src/share/vm/services/memTrackWorker.cpp @ 6197:d2a62e0f25eb
6995781: Native Memory Tracking (Phase 1)
7151532: DCmd for hotspot native memory tracking
Summary: Implementation of native memory tracking phase 1, which tracks VM native memory usage, and related DCmd
Reviewed-by: acorn, coleenp, fparain
author | zgu |
---|---|
date | Thu, 28 Jun 2012 17:03:16 -0400 |
parents | |
children | 4acebbe310e1 |
comparison
equal
deleted
inserted
replaced
6174:74533f63b116 | 6197:d2a62e0f25eb |
---|---|
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 | |
102 bool result = snapshot->merge(rec); | |
103 assert(result, "merge failed"); | |
104 debug_only(_merge_count ++;) | |
105 MemTracker::release_thread_recorder(rec); | |
106 } else { | |
107 // no more recorder to merge, promote staging area | |
108 // to snapshot | |
109 if (_head != _tail) { | |
110 { | |
111 ThreadCritical tc; | |
112 if (_gen[_head] != NULL || _head == _tail) { | |
113 continue; | |
114 } | |
115 // done with this generation, increment _head pointer | |
116 _head = (_head + 1) % MAX_GENERATIONS; | |
117 } | |
118 // promote this generation data to snapshot | |
119 snapshot->promote(); | |
120 } else { | |
121 snapshot->wait(1000); | |
122 ThreadCritical tc; | |
123 // check if more data arrived | |
124 if (_gen[_head] == NULL) { | |
125 _gen[_head] = MemTracker::get_pending_recorders(); | |
126 } | |
127 } | |
128 } | |
129 } | |
130 assert(MemTracker::shutdown_in_progress(), "just check"); | |
131 | |
132 // transites to final shutdown | |
133 MemTracker::final_shutdown(); | |
134 } | |
135 | |
136 // at synchronization point, where 'safepoint visible' Java threads are blocked | |
137 // at a safepoint, and the rest of threads are blocked on ThreadCritical lock. | |
138 // The caller MemTracker::sync() already takes ThreadCritical before calling this | |
139 // method. | |
140 // | |
141 // Following tasks are performed: | |
142 // 1. add all recorders in pending queue to current generation | |
143 // 2. increase generation | |
144 | |
145 void MemTrackWorker::at_sync_point(MemRecorder* rec) { | |
146 NOT_PRODUCT(_sync_point_count ++;) | |
147 assert(count_recorder(rec) <= MemRecorder::_instance_count, | |
148 "pending queue has infinite loop"); | |
149 | |
150 bool out_of_generation_buffer = false; | |
151 // check shutdown state inside ThreadCritical | |
152 if (MemTracker::shutdown_in_progress()) return; | |
153 // append the recorders to the end of the generation | |
154 if( rec != NULL) { | |
155 MemRecorder* cur_head = _gen[_tail]; | |
156 if (cur_head == NULL) { | |
157 _gen[_tail] = rec; | |
158 } else { | |
159 while (cur_head->next() != NULL) { | |
160 cur_head = cur_head->next(); | |
161 } | |
162 cur_head->set_next(rec); | |
163 } | |
164 } | |
165 assert(count_recorder(rec) <= MemRecorder::_instance_count, | |
166 "after add to current generation has infinite loop"); | |
167 // we have collected all recorders for this generation. If there is data, | |
168 // we need to increment _tail to start a new generation. | |
169 if (_gen[_tail] != NULL || _head == _tail) { | |
170 _tail = (_tail + 1) % MAX_GENERATIONS; | |
171 out_of_generation_buffer = (_tail == _head); | |
172 } | |
173 | |
174 if (out_of_generation_buffer) { | |
175 MemTracker::shutdown(MemTracker::NMT_out_of_generation); | |
176 } | |
177 } | |
178 | |
179 #ifndef PRODUCT | |
180 int MemTrackWorker::count_recorder(const MemRecorder* head) { | |
181 int count = 0; | |
182 while(head != NULL) { | |
183 count ++; | |
184 head = head->next(); | |
185 } | |
186 return count; | |
187 } | |
188 | |
189 int MemTrackWorker::count_pending_recorders() const { | |
190 int count = 0; | |
191 for (int index = 0; index < MAX_GENERATIONS; index ++) { | |
192 MemRecorder* head = _gen[index]; | |
193 if (head != NULL) { | |
194 count += count_recorder(head); | |
195 } | |
196 } | |
197 return count; | |
198 } | |
199 #endif |