Mercurial > hg > graal-jvmci-8
annotate src/share/vm/runtime/fprofiler.cpp @ 7432:0b3d19153cc6
8001028: Improve GC option handling
Summary: If there are not enough native resources to create the ReferenceHandler or Finalizer Java threads, the VM will attempt to throw an OOME before the java.lang.Class class has been initialized. This can result in assertion failures and other crashes. Move the initialization of the java.lang.Class class to just before the initialization of the java.lang.ref.Finalizer class.
Reviewed-by: jwilhelm, dholmes, coleenp
author | johnc |
---|---|
date | Wed, 12 Dec 2012 12:07:32 -0800 |
parents | da91efe96a93 |
children | aeaca88565e6 |
rev | line source |
---|---|
0 | 1 /* |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
605
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
605
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
605
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "classfile/classLoader.hpp" | |
27 #include "code/vtableStubs.hpp" | |
28 #include "gc_interface/collectedHeap.inline.hpp" | |
29 #include "interpreter/interpreter.hpp" | |
30 #include "memory/allocation.inline.hpp" | |
31 #include "memory/universe.inline.hpp" | |
32 #include "oops/oop.inline.hpp" | |
33 #include "oops/oop.inline2.hpp" | |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
1972
diff
changeset
|
34 #include "oops/symbol.hpp" |
1972 | 35 #include "runtime/deoptimization.hpp" |
36 #include "runtime/fprofiler.hpp" | |
37 #include "runtime/mutexLocker.hpp" | |
38 #include "runtime/stubCodeGenerator.hpp" | |
39 #include "runtime/stubRoutines.hpp" | |
40 #include "runtime/task.hpp" | |
41 #include "runtime/vframe.hpp" | |
42 #include "utilities/macros.hpp" | |
0 | 43 |
44 // Static fields of FlatProfiler | |
45 int FlatProfiler::received_gc_ticks = 0; | |
46 int FlatProfiler::vm_operation_ticks = 0; | |
47 int FlatProfiler::threads_lock_ticks = 0; | |
48 int FlatProfiler::class_loader_ticks = 0; | |
49 int FlatProfiler::extra_ticks = 0; | |
50 int FlatProfiler::blocked_ticks = 0; | |
51 int FlatProfiler::deopt_ticks = 0; | |
52 int FlatProfiler::unknown_ticks = 0; | |
53 int FlatProfiler::interpreter_ticks = 0; | |
54 int FlatProfiler::compiler_ticks = 0; | |
55 int FlatProfiler::received_ticks = 0; | |
56 int FlatProfiler::delivered_ticks = 0; | |
57 int* FlatProfiler::bytecode_ticks = NULL; | |
58 int* FlatProfiler::bytecode_ticks_stub = NULL; | |
59 int FlatProfiler::all_int_ticks = 0; | |
60 int FlatProfiler::all_comp_ticks = 0; | |
61 int FlatProfiler::all_ticks = 0; | |
62 bool FlatProfiler::full_profile_flag = false; | |
63 ThreadProfiler* FlatProfiler::thread_profiler = NULL; | |
64 ThreadProfiler* FlatProfiler::vm_thread_profiler = NULL; | |
65 FlatProfilerTask* FlatProfiler::task = NULL; | |
66 elapsedTimer FlatProfiler::timer; | |
67 int FlatProfiler::interval_ticks_previous = 0; | |
68 IntervalData* FlatProfiler::interval_data = NULL; | |
69 | |
70 ThreadProfiler::ThreadProfiler() { | |
71 // Space for the ProfilerNodes | |
72 const int area_size = 1 * ProfilerNodeSize * 1024; | |
6197 | 73 area_bottom = AllocateHeap(area_size, mtInternal); |
0 | 74 area_top = area_bottom; |
75 area_limit = area_bottom + area_size; | |
76 | |
77 // ProfilerNode pointer table | |
6197 | 78 table = NEW_C_HEAP_ARRAY(ProfilerNode*, table_size, mtInternal); |
0 | 79 initialize(); |
80 engaged = false; | |
81 } | |
82 | |
83 ThreadProfiler::~ThreadProfiler() { | |
84 FreeHeap(area_bottom); | |
85 area_bottom = NULL; | |
86 area_top = NULL; | |
87 area_limit = NULL; | |
88 FreeHeap(table); | |
89 table = NULL; | |
90 } | |
91 | |
92 // Statics for ThreadProfiler | |
93 int ThreadProfiler::table_size = 1024; | |
94 | |
95 int ThreadProfiler::entry(int value) { | |
96 value = (value > 0) ? value : -value; | |
97 return value % table_size; | |
98 } | |
99 | |
100 ThreadProfilerMark::ThreadProfilerMark(ThreadProfilerMark::Region r) { | |
101 _r = r; | |
102 _pp = NULL; | |
103 assert(((r > ThreadProfilerMark::noRegion) && (r < ThreadProfilerMark::maxRegion)), "ThreadProfilerMark::Region out of bounds"); | |
104 Thread* tp = Thread::current(); | |
105 if (tp != NULL && tp->is_Java_thread()) { | |
106 JavaThread* jtp = (JavaThread*) tp; | |
107 ThreadProfiler* pp = jtp->get_thread_profiler(); | |
108 _pp = pp; | |
109 if (pp != NULL) { | |
110 pp->region_flag[r] = true; | |
111 } | |
112 } | |
113 } | |
114 | |
115 ThreadProfilerMark::~ThreadProfilerMark() { | |
116 if (_pp != NULL) { | |
117 _pp->region_flag[_r] = false; | |
118 } | |
119 _pp = NULL; | |
120 } | |
121 | |
122 // Random other statics | |
123 static const int col1 = 2; // position of output column 1 | |
124 static const int col2 = 11; // position of output column 2 | |
125 static const int col3 = 25; // position of output column 3 | |
126 static const int col4 = 55; // position of output column 4 | |
127 | |
128 | |
129 // Used for detailed profiling of nmethods. | |
130 class PCRecorder : AllStatic { | |
131 private: | |
132 static int* counters; | |
133 static address base; | |
134 enum { | |
135 bucket_size = 16 | |
136 }; | |
137 static int index_for(address pc) { return (pc - base)/bucket_size; } | |
138 static address pc_for(int index) { return base + (index * bucket_size); } | |
139 static int size() { | |
140 return ((int)CodeCache::max_capacity())/bucket_size * BytesPerWord; | |
141 } | |
142 public: | |
143 static address bucket_start_for(address pc) { | |
144 if (counters == NULL) return NULL; | |
145 return pc_for(index_for(pc)); | |
146 } | |
147 static int bucket_count_for(address pc) { return counters[index_for(pc)]; } | |
148 static void init(); | |
149 static void record(address pc); | |
150 static void print(); | |
151 static void print_blobs(CodeBlob* cb); | |
152 }; | |
153 | |
154 int* PCRecorder::counters = NULL; | |
155 address PCRecorder::base = NULL; | |
156 | |
157 void PCRecorder::init() { | |
158 MutexLockerEx lm(CodeCache_lock, Mutex::_no_safepoint_check_flag); | |
159 int s = size(); | |
6197 | 160 counters = NEW_C_HEAP_ARRAY(int, s, mtInternal); |
0 | 161 for (int index = 0; index < s; index++) { |
162 counters[index] = 0; | |
163 } | |
164 base = CodeCache::first_address(); | |
165 } | |
166 | |
167 void PCRecorder::record(address pc) { | |
168 if (counters == NULL) return; | |
169 assert(CodeCache::contains(pc), "must be in CodeCache"); | |
170 counters[index_for(pc)]++; | |
171 } | |
172 | |
173 | |
174 address FlatProfiler::bucket_start_for(address pc) { | |
175 return PCRecorder::bucket_start_for(pc); | |
176 } | |
177 | |
178 int FlatProfiler::bucket_count_for(address pc) { | |
179 return PCRecorder::bucket_count_for(pc); | |
180 } | |
181 | |
182 void PCRecorder::print() { | |
183 if (counters == NULL) return; | |
184 | |
185 tty->cr(); | |
186 tty->print_cr("Printing compiled methods with PC buckets having more than %d ticks", ProfilerPCTickThreshold); | |
187 tty->print_cr("==================================================================="); | |
188 tty->cr(); | |
189 | |
190 GrowableArray<CodeBlob*>* candidates = new GrowableArray<CodeBlob*>(20); | |
191 | |
192 | |
193 int s; | |
194 { | |
195 MutexLockerEx lm(CodeCache_lock, Mutex::_no_safepoint_check_flag); | |
196 s = size(); | |
197 } | |
198 | |
199 for (int index = 0; index < s; index++) { | |
200 int count = counters[index]; | |
201 if (count > ProfilerPCTickThreshold) { | |
202 address pc = pc_for(index); | |
203 CodeBlob* cb = CodeCache::find_blob_unsafe(pc); | |
204 if (cb != NULL && candidates->find(cb) < 0) { | |
205 candidates->push(cb); | |
206 } | |
207 } | |
208 } | |
209 for (int i = 0; i < candidates->length(); i++) { | |
210 print_blobs(candidates->at(i)); | |
211 } | |
212 } | |
213 | |
214 void PCRecorder::print_blobs(CodeBlob* cb) { | |
215 if (cb != NULL) { | |
216 cb->print(); | |
217 if (cb->is_nmethod()) { | |
218 ((nmethod*)cb)->print_code(); | |
219 } | |
220 tty->cr(); | |
221 } else { | |
222 tty->print_cr("stub code"); | |
223 } | |
224 } | |
225 | |
226 class tick_counter { // holds tick info for one node | |
227 public: | |
228 int ticks_in_code; | |
229 int ticks_in_native; | |
230 | |
231 tick_counter() { ticks_in_code = ticks_in_native = 0; } | |
232 tick_counter(int code, int native) { ticks_in_code = code; ticks_in_native = native; } | |
233 | |
234 int total() const { | |
235 return (ticks_in_code + ticks_in_native); | |
236 } | |
237 | |
238 void add(tick_counter* a) { | |
239 ticks_in_code += a->ticks_in_code; | |
240 ticks_in_native += a->ticks_in_native; | |
241 } | |
242 | |
243 void update(TickPosition where) { | |
244 switch(where) { | |
245 case tp_code: ticks_in_code++; break; | |
246 case tp_native: ticks_in_native++; break; | |
247 } | |
248 } | |
249 | |
250 void print_code(outputStream* st, int total_ticks) { | |
251 st->print("%5.1f%% %5d ", total() * 100.0 / total_ticks, ticks_in_code); | |
252 } | |
253 | |
254 void print_native(outputStream* st) { | |
255 st->print(" + %5d ", ticks_in_native); | |
256 } | |
257 }; | |
258 | |
259 class ProfilerNode { | |
260 private: | |
261 ProfilerNode* _next; | |
262 public: | |
263 tick_counter ticks; | |
264 | |
265 public: | |
266 | |
267 void* operator new(size_t size, ThreadProfiler* tp); | |
268 void operator delete(void* p); | |
269 | |
270 ProfilerNode() { | |
271 _next = NULL; | |
272 } | |
273 | |
274 virtual ~ProfilerNode() { | |
275 if (_next) | |
276 delete _next; | |
277 } | |
278 | |
279 void set_next(ProfilerNode* n) { _next = n; } | |
280 ProfilerNode* next() { return _next; } | |
281 | |
282 void update(TickPosition where) { ticks.update(where);} | |
283 int total_ticks() { return ticks.total(); } | |
284 | |
285 virtual bool is_interpreted() const { return false; } | |
286 virtual bool is_compiled() const { return false; } | |
287 virtual bool is_stub() const { return false; } | |
288 virtual bool is_runtime_stub() const{ return false; } | |
289 virtual void oops_do(OopClosure* f) = 0; | |
290 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
291 virtual bool interpreted_match(Method* m) const { return false; } |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
292 virtual bool compiled_match(Method* m ) const { return false; } |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
293 virtual bool stub_match(Method* m, const char* name) const { return false; } |
0 | 294 virtual bool adapter_match() const { return false; } |
295 virtual bool runtimeStub_match(const CodeBlob* stub, const char* name) const { return false; } | |
296 virtual bool unknown_compiled_match(const CodeBlob* cb) const { return false; } | |
297 | |
298 static void print_title(outputStream* st) { | |
299 st->print(" + native"); | |
300 st->fill_to(col3); | |
301 st->print("Method"); | |
302 st->fill_to(col4); | |
303 st->cr(); | |
304 } | |
305 | |
306 static void print_total(outputStream* st, tick_counter* t, int total, const char* msg) { | |
307 t->print_code(st, total); | |
308 st->fill_to(col2); | |
309 t->print_native(st); | |
310 st->fill_to(col3); | |
311 st->print(msg); | |
312 st->cr(); | |
313 } | |
314 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
315 virtual Method* method() = 0; |
0 | 316 |
317 virtual void print_method_on(outputStream* st) { | |
318 int limit; | |
319 int i; | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
320 Method* m = method(); |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
1972
diff
changeset
|
321 Symbol* k = m->klass_name(); |
0 | 322 // Print the class name with dots instead of slashes |
323 limit = k->utf8_length(); | |
324 for (i = 0 ; i < limit ; i += 1) { | |
325 char c = (char) k->byte_at(i); | |
326 if (c == '/') { | |
327 c = '.'; | |
328 } | |
329 st->print("%c", c); | |
330 } | |
331 if (limit > 0) { | |
332 st->print("."); | |
333 } | |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
1972
diff
changeset
|
334 Symbol* n = m->name(); |
0 | 335 limit = n->utf8_length(); |
336 for (i = 0 ; i < limit ; i += 1) { | |
337 char c = (char) n->byte_at(i); | |
338 st->print("%c", c); | |
339 } | |
6266
1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
twisti
parents:
6197
diff
changeset
|
340 if (Verbose || WizardMode) { |
0 | 341 // Disambiguate overloaded methods |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
1972
diff
changeset
|
342 Symbol* sig = m->signature(); |
0 | 343 sig->print_symbol_on(st); |
6266
1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
twisti
parents:
6197
diff
changeset
|
344 } else if (MethodHandles::is_signature_polymorphic(m->intrinsic_id())) |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
345 // compare with Method::print_short_name |
6266
1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
twisti
parents:
6197
diff
changeset
|
346 MethodHandles::print_as_basic_type_signature_on(st, m->signature(), true); |
0 | 347 } |
348 | |
349 virtual void print(outputStream* st, int total_ticks) { | |
350 ticks.print_code(st, total_ticks); | |
351 st->fill_to(col2); | |
352 ticks.print_native(st); | |
353 st->fill_to(col3); | |
354 print_method_on(st); | |
355 st->cr(); | |
356 } | |
357 | |
358 // for hashing into the table | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
359 static int hash(Method* method) { |
0 | 360 // The point here is to try to make something fairly unique |
361 // out of the fields we can read without grabbing any locks | |
362 // since the method may be locked when we need the hash. | |
363 return ( | |
364 method->code_size() ^ | |
365 method->max_stack() ^ | |
366 method->max_locals() ^ | |
367 method->size_of_parameters()); | |
368 } | |
369 | |
370 // for sorting | |
371 static int compare(ProfilerNode** a, ProfilerNode** b) { | |
372 return (*b)->total_ticks() - (*a)->total_ticks(); | |
373 } | |
374 }; | |
375 | |
376 void* ProfilerNode::operator new(size_t size, ThreadProfiler* tp){ | |
377 void* result = (void*) tp->area_top; | |
378 tp->area_top += size; | |
379 | |
380 if (tp->area_top > tp->area_limit) { | |
381 fatal("flat profiler buffer overflow"); | |
382 } | |
383 return result; | |
384 } | |
385 | |
386 void ProfilerNode::operator delete(void* p){ | |
387 } | |
388 | |
389 class interpretedNode : public ProfilerNode { | |
390 private: | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
391 Method* _method; |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
392 oop _class_loader; // needed to keep metadata for the method alive |
0 | 393 public: |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
394 interpretedNode(Method* method, TickPosition where) : ProfilerNode() { |
0 | 395 _method = method; |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
396 _class_loader = method->method_holder()->class_loader(); |
0 | 397 update(where); |
398 } | |
399 | |
400 bool is_interpreted() const { return true; } | |
401 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
402 bool interpreted_match(Method* m) const { |
0 | 403 return _method == m; |
404 } | |
405 | |
406 void oops_do(OopClosure* f) { | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
407 f->do_oop(&_class_loader); |
0 | 408 } |
409 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
410 Method* method() { return _method; } |
0 | 411 |
412 static void print_title(outputStream* st) { | |
413 st->fill_to(col1); | |
414 st->print("%11s", "Interpreted"); | |
415 ProfilerNode::print_title(st); | |
416 } | |
417 | |
418 void print(outputStream* st, int total_ticks) { | |
419 ProfilerNode::print(st, total_ticks); | |
420 } | |
421 | |
422 void print_method_on(outputStream* st) { | |
423 ProfilerNode::print_method_on(st); | |
424 if (Verbose) method()->invocation_counter()->print_short(); | |
425 } | |
426 }; | |
427 | |
428 class compiledNode : public ProfilerNode { | |
429 private: | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
430 Method* _method; |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
431 oop _class_loader; // needed to keep metadata for the method alive |
0 | 432 public: |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
433 compiledNode(Method* method, TickPosition where) : ProfilerNode() { |
0 | 434 _method = method; |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
435 _class_loader = method->method_holder()->class_loader(); |
0 | 436 update(where); |
437 } | |
438 bool is_compiled() const { return true; } | |
439 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
440 bool compiled_match(Method* m) const { |
0 | 441 return _method == m; |
442 } | |
443 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
444 Method* method() { return _method; } |
0 | 445 |
446 void oops_do(OopClosure* f) { | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
447 f->do_oop(&_class_loader); |
0 | 448 } |
449 | |
450 static void print_title(outputStream* st) { | |
451 st->fill_to(col1); | |
452 st->print("%11s", "Compiled"); | |
453 ProfilerNode::print_title(st); | |
454 } | |
455 | |
456 void print(outputStream* st, int total_ticks) { | |
457 ProfilerNode::print(st, total_ticks); | |
458 } | |
459 | |
460 void print_method_on(outputStream* st) { | |
461 ProfilerNode::print_method_on(st); | |
462 } | |
463 }; | |
464 | |
465 class stubNode : public ProfilerNode { | |
466 private: | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
467 Method* _method; |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
468 oop _class_loader; // needed to keep metadata for the method alive |
0 | 469 const char* _symbol; // The name of the nearest VM symbol (for +ProfileVM). Points to a unique string |
470 public: | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
471 stubNode(Method* method, const char* name, TickPosition where) : ProfilerNode() { |
0 | 472 _method = method; |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
473 _class_loader = method->method_holder()->class_loader(); |
0 | 474 _symbol = name; |
475 update(where); | |
476 } | |
477 | |
478 bool is_stub() const { return true; } | |
479 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
480 void oops_do(OopClosure* f) { |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
481 f->do_oop(&_class_loader); |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
482 } |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
483 |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
484 bool stub_match(Method* m, const char* name) const { |
0 | 485 return (_method == m) && (_symbol == name); |
486 } | |
487 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
488 Method* method() { return _method; } |
0 | 489 |
490 static void print_title(outputStream* st) { | |
491 st->fill_to(col1); | |
492 st->print("%11s", "Stub"); | |
493 ProfilerNode::print_title(st); | |
494 } | |
495 | |
496 void print(outputStream* st, int total_ticks) { | |
497 ProfilerNode::print(st, total_ticks); | |
498 } | |
499 | |
500 void print_method_on(outputStream* st) { | |
501 ProfilerNode::print_method_on(st); | |
502 print_symbol_on(st); | |
503 } | |
504 | |
505 void print_symbol_on(outputStream* st) { | |
506 if(_symbol) { | |
507 st->print(" (%s)", _symbol); | |
508 } | |
509 } | |
510 }; | |
511 | |
512 class adapterNode : public ProfilerNode { | |
513 public: | |
514 adapterNode(TickPosition where) : ProfilerNode() { | |
515 update(where); | |
516 } | |
517 bool is_compiled() const { return true; } | |
518 | |
519 bool adapter_match() const { return true; } | |
520 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
521 Method* method() { return NULL; } |
0 | 522 |
523 void oops_do(OopClosure* f) { | |
524 ; | |
525 } | |
526 | |
527 void print(outputStream* st, int total_ticks) { | |
528 ProfilerNode::print(st, total_ticks); | |
529 } | |
530 | |
531 void print_method_on(outputStream* st) { | |
532 st->print("%s", "adapters"); | |
533 } | |
534 }; | |
535 | |
536 class runtimeStubNode : public ProfilerNode { | |
537 private: | |
538 const CodeBlob* _stub; | |
539 const char* _symbol; // The name of the nearest VM symbol when ProfileVM is on. Points to a unique string. | |
540 public: | |
541 runtimeStubNode(const CodeBlob* stub, const char* name, TickPosition where) : ProfilerNode(), _stub(stub), _symbol(name) { | |
542 assert(stub->is_runtime_stub(), "wrong code blob"); | |
543 update(where); | |
544 } | |
545 | |
546 bool is_runtime_stub() const { return true; } | |
547 | |
548 bool runtimeStub_match(const CodeBlob* stub, const char* name) const { | |
549 assert(stub->is_runtime_stub(), "wrong code blob"); | |
550 return ((RuntimeStub*)_stub)->entry_point() == ((RuntimeStub*)stub)->entry_point() && | |
551 (_symbol == name); | |
552 } | |
553 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
554 Method* method() { return NULL; } |
0 | 555 |
556 static void print_title(outputStream* st) { | |
557 st->fill_to(col1); | |
558 st->print("%11s", "Runtime stub"); | |
559 ProfilerNode::print_title(st); | |
560 } | |
561 | |
562 void oops_do(OopClosure* f) { | |
563 ; | |
564 } | |
565 | |
566 void print(outputStream* st, int total_ticks) { | |
567 ProfilerNode::print(st, total_ticks); | |
568 } | |
569 | |
570 void print_method_on(outputStream* st) { | |
571 st->print("%s", ((RuntimeStub*)_stub)->name()); | |
572 print_symbol_on(st); | |
573 } | |
574 | |
575 void print_symbol_on(outputStream* st) { | |
576 if(_symbol) { | |
577 st->print(" (%s)", _symbol); | |
578 } | |
579 } | |
580 }; | |
581 | |
582 | |
583 class unknown_compiledNode : public ProfilerNode { | |
584 const char *_name; | |
585 public: | |
586 unknown_compiledNode(const CodeBlob* cb, TickPosition where) : ProfilerNode() { | |
587 if ( cb->is_buffer_blob() ) | |
588 _name = ((BufferBlob*)cb)->name(); | |
589 else | |
590 _name = ((SingletonBlob*)cb)->name(); | |
591 update(where); | |
592 } | |
593 bool is_compiled() const { return true; } | |
594 | |
595 bool unknown_compiled_match(const CodeBlob* cb) const { | |
596 if ( cb->is_buffer_blob() ) | |
597 return !strcmp(((BufferBlob*)cb)->name(), _name); | |
598 else | |
599 return !strcmp(((SingletonBlob*)cb)->name(), _name); | |
600 } | |
601 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
602 Method* method() { return NULL; } |
0 | 603 |
604 void oops_do(OopClosure* f) { | |
605 ; | |
606 } | |
607 | |
608 void print(outputStream* st, int total_ticks) { | |
609 ProfilerNode::print(st, total_ticks); | |
610 } | |
611 | |
612 void print_method_on(outputStream* st) { | |
613 st->print("%s", _name); | |
614 } | |
615 }; | |
616 | |
617 class vmNode : public ProfilerNode { | |
618 private: | |
619 const char* _name; // "optional" name obtained by os means such as dll lookup | |
620 public: | |
621 vmNode(const TickPosition where) : ProfilerNode() { | |
622 _name = NULL; | |
623 update(where); | |
624 } | |
625 | |
626 vmNode(const char* name, const TickPosition where) : ProfilerNode() { | |
627 _name = name; | |
628 update(where); | |
629 } | |
630 | |
631 const char *name() const { return _name; } | |
632 bool is_compiled() const { return true; } | |
633 | |
634 bool vm_match(const char* name) const { return strcmp(name, _name) == 0; } | |
635 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
636 Method* method() { return NULL; } |
0 | 637 |
638 static int hash(const char* name){ | |
639 // Compute a simple hash | |
640 const char* cp = name; | |
641 int h = 0; | |
642 | |
643 if(name != NULL){ | |
644 while(*cp != '\0'){ | |
645 h = (h << 1) ^ *cp; | |
646 cp++; | |
647 } | |
648 } | |
649 return h; | |
650 } | |
651 | |
652 void oops_do(OopClosure* f) { | |
653 ; | |
654 } | |
655 | |
656 void print(outputStream* st, int total_ticks) { | |
657 ProfilerNode::print(st, total_ticks); | |
658 } | |
659 | |
660 void print_method_on(outputStream* st) { | |
661 if(_name==NULL){ | |
662 st->print("%s", "unknown code"); | |
663 } | |
664 else { | |
665 st->print("%s", _name); | |
666 } | |
667 } | |
668 }; | |
669 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
670 void ThreadProfiler::interpreted_update(Method* method, TickPosition where) { |
0 | 671 int index = entry(ProfilerNode::hash(method)); |
672 if (!table[index]) { | |
673 table[index] = new (this) interpretedNode(method, where); | |
674 } else { | |
675 ProfilerNode* prev = table[index]; | |
676 for(ProfilerNode* node = prev; node; node = node->next()) { | |
677 if (node->interpreted_match(method)) { | |
678 node->update(where); | |
679 return; | |
680 } | |
681 prev = node; | |
682 } | |
683 prev->set_next(new (this) interpretedNode(method, where)); | |
684 } | |
685 } | |
686 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
687 void ThreadProfiler::compiled_update(Method* method, TickPosition where) { |
0 | 688 int index = entry(ProfilerNode::hash(method)); |
689 if (!table[index]) { | |
690 table[index] = new (this) compiledNode(method, where); | |
691 } else { | |
692 ProfilerNode* prev = table[index]; | |
693 for(ProfilerNode* node = prev; node; node = node->next()) { | |
694 if (node->compiled_match(method)) { | |
695 node->update(where); | |
696 return; | |
697 } | |
698 prev = node; | |
699 } | |
700 prev->set_next(new (this) compiledNode(method, where)); | |
701 } | |
702 } | |
703 | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
704 void ThreadProfiler::stub_update(Method* method, const char* name, TickPosition where) { |
0 | 705 int index = entry(ProfilerNode::hash(method)); |
706 if (!table[index]) { | |
707 table[index] = new (this) stubNode(method, name, where); | |
708 } else { | |
709 ProfilerNode* prev = table[index]; | |
710 for(ProfilerNode* node = prev; node; node = node->next()) { | |
711 if (node->stub_match(method, name)) { | |
712 node->update(where); | |
713 return; | |
714 } | |
715 prev = node; | |
716 } | |
717 prev->set_next(new (this) stubNode(method, name, where)); | |
718 } | |
719 } | |
720 | |
721 void ThreadProfiler::adapter_update(TickPosition where) { | |
722 int index = 0; | |
723 if (!table[index]) { | |
724 table[index] = new (this) adapterNode(where); | |
725 } else { | |
726 ProfilerNode* prev = table[index]; | |
727 for(ProfilerNode* node = prev; node; node = node->next()) { | |
728 if (node->adapter_match()) { | |
729 node->update(where); | |
730 return; | |
731 } | |
732 prev = node; | |
733 } | |
734 prev->set_next(new (this) adapterNode(where)); | |
735 } | |
736 } | |
737 | |
738 void ThreadProfiler::runtime_stub_update(const CodeBlob* stub, const char* name, TickPosition where) { | |
739 int index = 0; | |
740 if (!table[index]) { | |
741 table[index] = new (this) runtimeStubNode(stub, name, where); | |
742 } else { | |
743 ProfilerNode* prev = table[index]; | |
744 for(ProfilerNode* node = prev; node; node = node->next()) { | |
745 if (node->runtimeStub_match(stub, name)) { | |
746 node->update(where); | |
747 return; | |
748 } | |
749 prev = node; | |
750 } | |
751 prev->set_next(new (this) runtimeStubNode(stub, name, where)); | |
752 } | |
753 } | |
754 | |
755 | |
756 void ThreadProfiler::unknown_compiled_update(const CodeBlob* cb, TickPosition where) { | |
757 int index = 0; | |
758 if (!table[index]) { | |
759 table[index] = new (this) unknown_compiledNode(cb, where); | |
760 } else { | |
761 ProfilerNode* prev = table[index]; | |
762 for(ProfilerNode* node = prev; node; node = node->next()) { | |
763 if (node->unknown_compiled_match(cb)) { | |
764 node->update(where); | |
765 return; | |
766 } | |
767 prev = node; | |
768 } | |
769 prev->set_next(new (this) unknown_compiledNode(cb, where)); | |
770 } | |
771 } | |
772 | |
773 void ThreadProfiler::vm_update(TickPosition where) { | |
774 vm_update(NULL, where); | |
775 } | |
776 | |
777 void ThreadProfiler::vm_update(const char* name, TickPosition where) { | |
778 int index = entry(vmNode::hash(name)); | |
779 assert(index >= 0, "Must be positive"); | |
780 // Note that we call strdup below since the symbol may be resource allocated | |
781 if (!table[index]) { | |
782 table[index] = new (this) vmNode(os::strdup(name), where); | |
783 } else { | |
784 ProfilerNode* prev = table[index]; | |
785 for(ProfilerNode* node = prev; node; node = node->next()) { | |
786 if (((vmNode *)node)->vm_match(name)) { | |
787 node->update(where); | |
788 return; | |
789 } | |
790 prev = node; | |
791 } | |
792 prev->set_next(new (this) vmNode(os::strdup(name), where)); | |
793 } | |
794 } | |
795 | |
796 | |
797 class FlatProfilerTask : public PeriodicTask { | |
798 public: | |
799 FlatProfilerTask(int interval_time) : PeriodicTask(interval_time) {} | |
800 void task(); | |
801 }; | |
802 | |
803 void FlatProfiler::record_vm_operation() { | |
804 if (Universe::heap()->is_gc_active()) { | |
805 FlatProfiler::received_gc_ticks += 1; | |
806 return; | |
807 } | |
808 | |
809 if (DeoptimizationMarker::is_active()) { | |
810 FlatProfiler::deopt_ticks += 1; | |
811 return; | |
812 } | |
813 | |
814 FlatProfiler::vm_operation_ticks += 1; | |
815 } | |
816 | |
817 void FlatProfiler::record_vm_tick() { | |
818 // Profile the VM Thread itself if needed | |
819 // This is done without getting the Threads_lock and we can go deep | |
820 // inside Safepoint, etc. | |
821 if( ProfileVM ) { | |
822 ResourceMark rm; | |
823 ExtendedPC epc; | |
824 const char *name = NULL; | |
825 char buf[256]; | |
826 buf[0] = '\0'; | |
827 | |
828 vm_thread_profiler->inc_thread_ticks(); | |
829 | |
830 // Get a snapshot of a current VMThread pc (and leave it running!) | |
831 // The call may fail if, for instance the VM thread is interrupted while | |
832 // holding the Interrupt_lock or for other reasons. | |
833 epc = os::get_thread_pc(VMThread::vm_thread()); | |
834 if(epc.pc() != NULL) { | |
835 if (os::dll_address_to_function_name(epc.pc(), buf, sizeof(buf), NULL)) { | |
836 name = buf; | |
837 } | |
838 } | |
839 if (name != NULL) { | |
840 vm_thread_profiler->vm_update(name, tp_native); | |
841 } | |
842 } | |
843 } | |
844 | |
845 void FlatProfiler::record_thread_ticks() { | |
846 | |
847 int maxthreads, suspendedthreadcount; | |
848 JavaThread** threadsList; | |
849 bool interval_expired = false; | |
850 | |
851 if (ProfileIntervals && | |
852 (FlatProfiler::received_ticks >= interval_ticks_previous + ProfileIntervalsTicks)) { | |
853 interval_expired = true; | |
854 interval_ticks_previous = FlatProfiler::received_ticks; | |
855 } | |
856 | |
857 // Try not to wait for the Threads_lock | |
858 if (Threads_lock->try_lock()) { | |
859 { // Threads_lock scope | |
860 maxthreads = Threads::number_of_threads(); | |
6197 | 861 threadsList = NEW_C_HEAP_ARRAY(JavaThread *, maxthreads, mtInternal); |
0 | 862 suspendedthreadcount = 0; |
863 for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { | |
864 if (tp->is_Compiler_thread()) { | |
865 // Only record ticks for active compiler threads | |
866 CompilerThread* cthread = (CompilerThread*)tp; | |
867 if (cthread->task() != NULL) { | |
868 // The compiler is active. If we need to access any of the fields | |
869 // of the compiler task we should suspend the CompilerThread first. | |
870 FlatProfiler::compiler_ticks += 1; | |
871 continue; | |
872 } | |
873 } | |
874 | |
875 // First externally suspend all threads by marking each for | |
876 // external suspension - so it will stop at its next transition | |
877 // Then do a safepoint | |
878 ThreadProfiler* pp = tp->get_thread_profiler(); | |
879 if (pp != NULL && pp->engaged) { | |
880 MutexLockerEx ml(tp->SR_lock(), Mutex::_no_safepoint_check_flag); | |
881 if (!tp->is_external_suspend() && !tp->is_exiting()) { | |
882 tp->set_external_suspend(); | |
883 threadsList[suspendedthreadcount++] = tp; | |
884 } | |
885 } | |
886 } | |
887 Threads_lock->unlock(); | |
888 } | |
889 // Suspend each thread. This call should just return | |
890 // for any threads that have already self-suspended | |
891 // Net result should be one safepoint | |
892 for (int j = 0; j < suspendedthreadcount; j++) { | |
893 JavaThread *tp = threadsList[j]; | |
894 if (tp) { | |
895 tp->java_suspend(); | |
896 } | |
897 } | |
898 | |
899 // We are responsible for resuming any thread on this list | |
900 for (int i = 0; i < suspendedthreadcount; i++) { | |
901 JavaThread *tp = threadsList[i]; | |
902 if (tp) { | |
903 ThreadProfiler* pp = tp->get_thread_profiler(); | |
904 if (pp != NULL && pp->engaged) { | |
905 HandleMark hm; | |
906 FlatProfiler::delivered_ticks += 1; | |
907 if (interval_expired) { | |
908 FlatProfiler::interval_record_thread(pp); | |
909 } | |
910 // This is the place where we check to see if a user thread is | |
911 // blocked waiting for compilation. | |
912 if (tp->blocked_on_compilation()) { | |
913 pp->compiler_ticks += 1; | |
914 pp->interval_data_ref()->inc_compiling(); | |
915 } else { | |
916 pp->record_tick(tp); | |
917 } | |
918 } | |
919 MutexLocker ml(Threads_lock); | |
920 tp->java_resume(); | |
921 } | |
922 } | |
923 if (interval_expired) { | |
924 FlatProfiler::interval_print(); | |
925 FlatProfiler::interval_reset(); | |
926 } | |
927 } else { | |
928 // Couldn't get the threads lock, just record that rather than blocking | |
929 FlatProfiler::threads_lock_ticks += 1; | |
930 } | |
931 | |
932 } | |
933 | |
934 void FlatProfilerTask::task() { | |
935 FlatProfiler::received_ticks += 1; | |
936 | |
937 if (ProfileVM) { | |
938 FlatProfiler::record_vm_tick(); | |
939 } | |
940 | |
941 VM_Operation* op = VMThread::vm_operation(); | |
942 if (op != NULL) { | |
943 FlatProfiler::record_vm_operation(); | |
944 if (SafepointSynchronize::is_at_safepoint()) { | |
945 return; | |
946 } | |
947 } | |
948 FlatProfiler::record_thread_ticks(); | |
949 } | |
950 | |
107
93b6525e3b82
6603919: Stackwalking crash on x86 -server with Sun Studio's collect -j on
sgoldman
parents:
0
diff
changeset
|
951 void ThreadProfiler::record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks) { |
0 | 952 FlatProfiler::all_int_ticks++; |
953 if (!FlatProfiler::full_profile()) { | |
954 return; | |
955 } | |
956 | |
107
93b6525e3b82
6603919: Stackwalking crash on x86 -server with Sun Studio's collect -j on
sgoldman
parents:
0
diff
changeset
|
957 if (!fr.is_interpreted_frame_valid(thread)) { |
0 | 958 // tick came at a bad time |
959 interpreter_ticks += 1; | |
960 FlatProfiler::interpreter_ticks += 1; | |
961 return; | |
962 } | |
963 | |
107
93b6525e3b82
6603919: Stackwalking crash on x86 -server with Sun Studio's collect -j on
sgoldman
parents:
0
diff
changeset
|
964 // The frame has been fully validated so we can trust the method and bci |
93b6525e3b82
6603919: Stackwalking crash on x86 -server with Sun Studio's collect -j on
sgoldman
parents:
0
diff
changeset
|
965 |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
966 Method* method = *fr.interpreter_frame_method_addr(); |
107
93b6525e3b82
6603919: Stackwalking crash on x86 -server with Sun Studio's collect -j on
sgoldman
parents:
0
diff
changeset
|
967 |
0 | 968 interpreted_update(method, where); |
969 | |
970 // update byte code table | |
971 InterpreterCodelet* desc = Interpreter::codelet_containing(fr.pc()); | |
972 if (desc != NULL && desc->bytecode() >= 0) { | |
973 ticks[desc->bytecode()]++; | |
974 } | |
975 } | |
976 | |
977 void ThreadProfiler::record_compiled_tick(JavaThread* thread, frame fr, TickPosition where) { | |
978 const char *name = NULL; | |
979 TickPosition localwhere = where; | |
980 | |
981 FlatProfiler::all_comp_ticks++; | |
982 if (!FlatProfiler::full_profile()) return; | |
983 | |
984 CodeBlob* cb = fr.cb(); | |
985 | |
986 // For runtime stubs, record as native rather than as compiled | |
987 if (cb->is_runtime_stub()) { | |
988 RegisterMap map(thread, false); | |
989 fr = fr.sender(&map); | |
990 cb = fr.cb(); | |
991 localwhere = tp_native; | |
992 } | |
6725
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
993 Method* method = (cb->is_nmethod()) ? ((nmethod *)cb)->method() : |
da91efe96a93
6964458: Reimplement class meta-data storage to use native memory
coleenp
parents:
6266
diff
changeset
|
994 (Method*)NULL; |
0 | 995 |
996 if (method == NULL) { | |
997 if (cb->is_runtime_stub()) | |
998 runtime_stub_update(cb, name, localwhere); | |
999 else | |
1000 unknown_compiled_update(cb, localwhere); | |
1001 } | |
1002 else { | |
1003 if (method->is_native()) { | |
1004 stub_update(method, name, localwhere); | |
1005 } else { | |
1006 compiled_update(method, localwhere); | |
1007 } | |
1008 } | |
1009 } | |
1010 | |
1011 extern "C" void find(int x); | |
1012 | |
1013 | |
1014 void ThreadProfiler::record_tick_for_running_frame(JavaThread* thread, frame fr) { | |
605 | 1015 // The tick happened in real code -> non VM code |
0 | 1016 if (fr.is_interpreted_frame()) { |
1017 interval_data_ref()->inc_interpreted(); | |
107
93b6525e3b82
6603919: Stackwalking crash on x86 -server with Sun Studio's collect -j on
sgoldman
parents:
0
diff
changeset
|
1018 record_interpreted_tick(thread, fr, tp_code, FlatProfiler::bytecode_ticks); |
0 | 1019 return; |
1020 } | |
1021 | |
1022 if (CodeCache::contains(fr.pc())) { | |
1023 interval_data_ref()->inc_compiled(); | |
1024 PCRecorder::record(fr.pc()); | |
1025 record_compiled_tick(thread, fr, tp_code); | |
1026 return; | |
1027 } | |
1028 | |
1029 if (VtableStubs::stub_containing(fr.pc()) != NULL) { | |
1030 unknown_ticks_array[ut_vtable_stubs] += 1; | |
1031 return; | |
1032 } | |
1033 | |
1034 frame caller = fr.profile_find_Java_sender_frame(thread); | |
1035 | |
1036 if (caller.sp() != NULL && caller.pc() != NULL) { | |
1037 record_tick_for_calling_frame(thread, caller); | |
1038 return; | |
1039 } | |
1040 | |
1041 unknown_ticks_array[ut_running_frame] += 1; | |
1042 FlatProfiler::unknown_ticks += 1; | |
1043 } | |
1044 | |
1045 void ThreadProfiler::record_tick_for_calling_frame(JavaThread* thread, frame fr) { | |
605 | 1046 // The tick happened in VM code |
0 | 1047 interval_data_ref()->inc_native(); |
1048 if (fr.is_interpreted_frame()) { | |
107
93b6525e3b82
6603919: Stackwalking crash on x86 -server with Sun Studio's collect -j on
sgoldman
parents:
0
diff
changeset
|
1049 record_interpreted_tick(thread, fr, tp_native, FlatProfiler::bytecode_ticks_stub); |
0 | 1050 return; |
1051 } | |
1052 if (CodeCache::contains(fr.pc())) { | |
1053 record_compiled_tick(thread, fr, tp_native); | |
1054 return; | |
1055 } | |
1056 | |
1057 frame caller = fr.profile_find_Java_sender_frame(thread); | |
1058 | |
1059 if (caller.sp() != NULL && caller.pc() != NULL) { | |
1060 record_tick_for_calling_frame(thread, caller); | |
1061 return; | |
1062 } | |
1063 | |
1064 unknown_ticks_array[ut_calling_frame] += 1; | |
1065 FlatProfiler::unknown_ticks += 1; | |
1066 } | |
1067 | |
1068 void ThreadProfiler::record_tick(JavaThread* thread) { | |
1069 FlatProfiler::all_ticks++; | |
1070 thread_ticks += 1; | |
1071 | |
1072 // Here's another way to track global state changes. | |
1073 // When the class loader starts it marks the ThreadProfiler to tell it it is in the class loader | |
1074 // and we check that here. | |
1075 // This is more direct, and more than one thread can be in the class loader at a time, | |
1076 // but it does mean the class loader has to know about the profiler. | |
1077 if (region_flag[ThreadProfilerMark::classLoaderRegion]) { | |
1078 class_loader_ticks += 1; | |
1079 FlatProfiler::class_loader_ticks += 1; | |
1080 return; | |
1081 } else if (region_flag[ThreadProfilerMark::extraRegion]) { | |
1082 extra_ticks += 1; | |
1083 FlatProfiler::extra_ticks += 1; | |
1084 return; | |
1085 } | |
1086 // Note that the WatcherThread can now stop for safepoints | |
1087 uint32_t debug_bits = 0; | |
1088 if (!thread->wait_for_ext_suspend_completion(SuspendRetryCount, | |
1089 SuspendRetryDelay, &debug_bits)) { | |
1090 unknown_ticks_array[ut_unknown_thread_state] += 1; | |
1091 FlatProfiler::unknown_ticks += 1; | |
1092 return; | |
1093 } | |
1094 | |
1095 frame fr; | |
1096 | |
1097 switch (thread->thread_state()) { | |
1098 case _thread_in_native: | |
1099 case _thread_in_native_trans: | |
1100 case _thread_in_vm: | |
1101 case _thread_in_vm_trans: | |
1102 if (thread->profile_last_Java_frame(&fr)) { | |
1103 if (fr.is_runtime_frame()) { | |
1104 RegisterMap map(thread, false); | |
1105 fr = fr.sender(&map); | |
1106 } | |
1107 record_tick_for_calling_frame(thread, fr); | |
1108 } else { | |
1109 unknown_ticks_array[ut_no_last_Java_frame] += 1; | |
1110 FlatProfiler::unknown_ticks += 1; | |
1111 } | |
1112 break; | |
1113 // handle_special_runtime_exit_condition self-suspends threads in Java | |
1114 case _thread_in_Java: | |
1115 case _thread_in_Java_trans: | |
1116 if (thread->profile_last_Java_frame(&fr)) { | |
1117 if (fr.is_safepoint_blob_frame()) { | |
1118 RegisterMap map(thread, false); | |
1119 fr = fr.sender(&map); | |
1120 } | |
1121 record_tick_for_running_frame(thread, fr); | |
1122 } else { | |
1123 unknown_ticks_array[ut_no_last_Java_frame] += 1; | |
1124 FlatProfiler::unknown_ticks += 1; | |
1125 } | |
1126 break; | |
1127 case _thread_blocked: | |
1128 case _thread_blocked_trans: | |
1129 if (thread->osthread() && thread->osthread()->get_state() == RUNNABLE) { | |
1130 if (thread->profile_last_Java_frame(&fr)) { | |
1131 if (fr.is_safepoint_blob_frame()) { | |
1132 RegisterMap map(thread, false); | |
1133 fr = fr.sender(&map); | |
1134 record_tick_for_running_frame(thread, fr); | |
1135 } else { | |
1136 record_tick_for_calling_frame(thread, fr); | |
1137 } | |
1138 } else { | |
1139 unknown_ticks_array[ut_no_last_Java_frame] += 1; | |
1140 FlatProfiler::unknown_ticks += 1; | |
1141 } | |
1142 } else { | |
1143 blocked_ticks += 1; | |
1144 FlatProfiler::blocked_ticks += 1; | |
1145 } | |
1146 break; | |
1147 case _thread_uninitialized: | |
1148 case _thread_new: | |
1149 // not used, included for completeness | |
1150 case _thread_new_trans: | |
1151 unknown_ticks_array[ut_no_last_Java_frame] += 1; | |
1152 FlatProfiler::unknown_ticks += 1; | |
1153 break; | |
1154 default: | |
1155 unknown_ticks_array[ut_unknown_thread_state] += 1; | |
1156 FlatProfiler::unknown_ticks += 1; | |
1157 break; | |
1158 } | |
1159 return; | |
1160 } | |
1161 | |
1162 void ThreadProfiler::engage() { | |
1163 engaged = true; | |
1164 timer.start(); | |
1165 } | |
1166 | |
1167 void ThreadProfiler::disengage() { | |
1168 engaged = false; | |
1169 timer.stop(); | |
1170 } | |
1171 | |
1172 void ThreadProfiler::initialize() { | |
1173 for (int index = 0; index < table_size; index++) { | |
1174 table[index] = NULL; | |
1175 } | |
1176 thread_ticks = 0; | |
1177 blocked_ticks = 0; | |
1178 compiler_ticks = 0; | |
1179 interpreter_ticks = 0; | |
1180 for (int ut = 0; ut < ut_end; ut += 1) { | |
1181 unknown_ticks_array[ut] = 0; | |
1182 } | |
1183 region_flag[ThreadProfilerMark::classLoaderRegion] = false; | |
1184 class_loader_ticks = 0; | |
1185 region_flag[ThreadProfilerMark::extraRegion] = false; | |
1186 extra_ticks = 0; | |
1187 timer.start(); | |
1188 interval_data_ref()->reset(); | |
1189 } | |
1190 | |
1191 void ThreadProfiler::reset() { | |
1192 timer.stop(); | |
1193 if (table != NULL) { | |
1194 for (int index = 0; index < table_size; index++) { | |
1195 ProfilerNode* n = table[index]; | |
1196 if (n != NULL) { | |
1197 delete n; | |
1198 } | |
1199 } | |
1200 } | |
1201 initialize(); | |
1202 } | |
1203 | |
1204 void FlatProfiler::allocate_table() { | |
1205 { // Bytecode table | |
6197 | 1206 bytecode_ticks = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes, mtInternal); |
1207 bytecode_ticks_stub = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes, mtInternal); | |
0 | 1208 for(int index = 0; index < Bytecodes::number_of_codes; index++) { |
1209 bytecode_ticks[index] = 0; | |
1210 bytecode_ticks_stub[index] = 0; | |
1211 } | |
1212 } | |
1213 | |
1214 if (ProfilerRecordPC) PCRecorder::init(); | |
1215 | |
6197 | 1216 interval_data = NEW_C_HEAP_ARRAY(IntervalData, interval_print_size, mtInternal); |
0 | 1217 FlatProfiler::interval_reset(); |
1218 } | |
1219 | |
1220 void FlatProfiler::engage(JavaThread* mainThread, bool fullProfile) { | |
1221 full_profile_flag = fullProfile; | |
1222 if (bytecode_ticks == NULL) { | |
1223 allocate_table(); | |
1224 } | |
1225 if(ProfileVM && (vm_thread_profiler == NULL)){ | |
1226 vm_thread_profiler = new ThreadProfiler(); | |
1227 } | |
1228 if (task == NULL) { | |
1229 task = new FlatProfilerTask(WatcherThread::delay_interval); | |
1230 task->enroll(); | |
1231 } | |
1232 timer.start(); | |
1233 if (mainThread != NULL) { | |
1234 // When mainThread was created, it might not have a ThreadProfiler | |
1235 ThreadProfiler* pp = mainThread->get_thread_profiler(); | |
1236 if (pp == NULL) { | |
1237 mainThread->set_thread_profiler(new ThreadProfiler()); | |
1238 } else { | |
1239 pp->reset(); | |
1240 } | |
1241 mainThread->get_thread_profiler()->engage(); | |
1242 } | |
1243 // This is where we would assign thread_profiler | |
1244 // if we wanted only one thread_profiler for all threads. | |
1245 thread_profiler = NULL; | |
1246 } | |
1247 | |
1248 void FlatProfiler::disengage() { | |
1249 if (!task) { | |
1250 return; | |
1251 } | |
1252 timer.stop(); | |
1253 task->disenroll(); | |
1254 delete task; | |
1255 task = NULL; | |
1256 if (thread_profiler != NULL) { | |
1257 thread_profiler->disengage(); | |
1258 } else { | |
1259 MutexLocker tl(Threads_lock); | |
1260 for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { | |
1261 ThreadProfiler* pp = tp->get_thread_profiler(); | |
1262 if (pp != NULL) { | |
1263 pp->disengage(); | |
1264 } | |
1265 } | |
1266 } | |
1267 } | |
1268 | |
1269 void FlatProfiler::reset() { | |
1270 if (task) { | |
1271 disengage(); | |
1272 } | |
1273 | |
1274 class_loader_ticks = 0; | |
1275 extra_ticks = 0; | |
1276 received_gc_ticks = 0; | |
1277 vm_operation_ticks = 0; | |
1278 compiler_ticks = 0; | |
1279 deopt_ticks = 0; | |
1280 interpreter_ticks = 0; | |
1281 blocked_ticks = 0; | |
1282 unknown_ticks = 0; | |
1283 received_ticks = 0; | |
1284 delivered_ticks = 0; | |
1285 timer.stop(); | |
1286 } | |
1287 | |
1288 bool FlatProfiler::is_active() { | |
1289 return task != NULL; | |
1290 } | |
1291 | |
1292 void FlatProfiler::print_byte_code_statistics() { | |
1293 GrowableArray <ProfilerNode*>* array = new GrowableArray<ProfilerNode*>(200); | |
1294 | |
1295 tty->print_cr(" Bytecode ticks:"); | |
1296 for (int index = 0; index < Bytecodes::number_of_codes; index++) { | |
1297 if (FlatProfiler::bytecode_ticks[index] > 0 || FlatProfiler::bytecode_ticks_stub[index] > 0) { | |
1298 tty->print_cr(" %4d %4d = %s", | |
1299 FlatProfiler::bytecode_ticks[index], | |
1300 FlatProfiler::bytecode_ticks_stub[index], | |
1301 Bytecodes::name( (Bytecodes::Code) index)); | |
1302 } | |
1303 } | |
1304 tty->cr(); | |
1305 } | |
1306 | |
1307 void print_ticks(const char* title, int ticks, int total) { | |
1308 if (ticks > 0) { | |
1309 tty->print("%5.1f%% %5d", ticks * 100.0 / total, ticks); | |
1310 tty->fill_to(col3); | |
1311 tty->print("%s", title); | |
1312 tty->cr(); | |
1313 } | |
1314 } | |
1315 | |
1316 void ThreadProfiler::print(const char* thread_name) { | |
1317 ResourceMark rm; | |
1318 MutexLocker ppl(ProfilePrint_lock); | |
1319 int index = 0; // Declared outside for loops for portability | |
1320 | |
1321 if (table == NULL) { | |
1322 return; | |
1323 } | |
1324 | |
1325 if (thread_ticks <= 0) { | |
1326 return; | |
1327 } | |
1328 | |
1329 const char* title = "too soon to tell"; | |
1330 double secs = timer.seconds(); | |
1331 | |
1332 GrowableArray <ProfilerNode*>* array = new GrowableArray<ProfilerNode*>(200); | |
1333 for(index = 0; index < table_size; index++) { | |
1334 for(ProfilerNode* node = table[index]; node; node = node->next()) | |
1335 array->append(node); | |
1336 } | |
1337 | |
1338 array->sort(&ProfilerNode::compare); | |
1339 | |
1340 // compute total (sanity check) | |
1341 int active = | |
1342 class_loader_ticks + | |
1343 compiler_ticks + | |
1344 interpreter_ticks + | |
1345 unknown_ticks(); | |
1346 for (index = 0; index < array->length(); index++) { | |
1347 active += array->at(index)->ticks.total(); | |
1348 } | |
1349 int total = active + blocked_ticks; | |
1350 | |
1351 tty->cr(); | |
1352 tty->print_cr("Flat profile of %3.2f secs (%d total ticks): %s", secs, total, thread_name); | |
1353 if (total != thread_ticks) { | |
1354 print_ticks("Lost ticks", thread_ticks-total, thread_ticks); | |
1355 } | |
1356 tty->cr(); | |
1357 | |
1358 // print interpreted methods | |
1359 tick_counter interpreted_ticks; | |
1360 bool has_interpreted_ticks = false; | |
1361 int print_count = 0; | |
1362 for (index = 0; index < array->length(); index++) { | |
1363 ProfilerNode* n = array->at(index); | |
1364 if (n->is_interpreted()) { | |
1365 interpreted_ticks.add(&n->ticks); | |
1366 if (!has_interpreted_ticks) { | |
1367 interpretedNode::print_title(tty); | |
1368 has_interpreted_ticks = true; | |
1369 } | |
1370 if (print_count++ < ProfilerNumberOfInterpretedMethods) { | |
1371 n->print(tty, active); | |
1372 } | |
1373 } | |
1374 } | |
1375 if (has_interpreted_ticks) { | |
1376 if (print_count <= ProfilerNumberOfInterpretedMethods) { | |
1377 title = "Total interpreted"; | |
1378 } else { | |
1379 title = "Total interpreted (including elided)"; | |
1380 } | |
1381 interpretedNode::print_total(tty, &interpreted_ticks, active, title); | |
1382 tty->cr(); | |
1383 } | |
1384 | |
1385 // print compiled methods | |
1386 tick_counter compiled_ticks; | |
1387 bool has_compiled_ticks = false; | |
1388 print_count = 0; | |
1389 for (index = 0; index < array->length(); index++) { | |
1390 ProfilerNode* n = array->at(index); | |
1391 if (n->is_compiled()) { | |
1392 compiled_ticks.add(&n->ticks); | |
1393 if (!has_compiled_ticks) { | |
1394 compiledNode::print_title(tty); | |
1395 has_compiled_ticks = true; | |
1396 } | |
1397 if (print_count++ < ProfilerNumberOfCompiledMethods) { | |
1398 n->print(tty, active); | |
1399 } | |
1400 } | |
1401 } | |
1402 if (has_compiled_ticks) { | |
1403 if (print_count <= ProfilerNumberOfCompiledMethods) { | |
1404 title = "Total compiled"; | |
1405 } else { | |
1406 title = "Total compiled (including elided)"; | |
1407 } | |
1408 compiledNode::print_total(tty, &compiled_ticks, active, title); | |
1409 tty->cr(); | |
1410 } | |
1411 | |
1412 // print stub methods | |
1413 tick_counter stub_ticks; | |
1414 bool has_stub_ticks = false; | |
1415 print_count = 0; | |
1416 for (index = 0; index < array->length(); index++) { | |
1417 ProfilerNode* n = array->at(index); | |
1418 if (n->is_stub()) { | |
1419 stub_ticks.add(&n->ticks); | |
1420 if (!has_stub_ticks) { | |
1421 stubNode::print_title(tty); | |
1422 has_stub_ticks = true; | |
1423 } | |
1424 if (print_count++ < ProfilerNumberOfStubMethods) { | |
1425 n->print(tty, active); | |
1426 } | |
1427 } | |
1428 } | |
1429 if (has_stub_ticks) { | |
1430 if (print_count <= ProfilerNumberOfStubMethods) { | |
1431 title = "Total stub"; | |
1432 } else { | |
1433 title = "Total stub (including elided)"; | |
1434 } | |
1435 stubNode::print_total(tty, &stub_ticks, active, title); | |
1436 tty->cr(); | |
1437 } | |
1438 | |
1439 // print runtime stubs | |
1440 tick_counter runtime_stub_ticks; | |
1441 bool has_runtime_stub_ticks = false; | |
1442 print_count = 0; | |
1443 for (index = 0; index < array->length(); index++) { | |
1444 ProfilerNode* n = array->at(index); | |
1445 if (n->is_runtime_stub()) { | |
1446 runtime_stub_ticks.add(&n->ticks); | |
1447 if (!has_runtime_stub_ticks) { | |
1448 runtimeStubNode::print_title(tty); | |
1449 has_runtime_stub_ticks = true; | |
1450 } | |
1451 if (print_count++ < ProfilerNumberOfRuntimeStubNodes) { | |
1452 n->print(tty, active); | |
1453 } | |
1454 } | |
1455 } | |
1456 if (has_runtime_stub_ticks) { | |
1457 if (print_count <= ProfilerNumberOfRuntimeStubNodes) { | |
1458 title = "Total runtime stubs"; | |
1459 } else { | |
1460 title = "Total runtime stubs (including elided)"; | |
1461 } | |
1462 runtimeStubNode::print_total(tty, &runtime_stub_ticks, active, title); | |
1463 tty->cr(); | |
1464 } | |
1465 | |
1466 if (blocked_ticks + class_loader_ticks + interpreter_ticks + compiler_ticks + unknown_ticks() != 0) { | |
1467 tty->fill_to(col1); | |
1468 tty->print_cr("Thread-local ticks:"); | |
1469 print_ticks("Blocked (of total)", blocked_ticks, total); | |
1470 print_ticks("Class loader", class_loader_ticks, active); | |
1471 print_ticks("Extra", extra_ticks, active); | |
1472 print_ticks("Interpreter", interpreter_ticks, active); | |
1473 print_ticks("Compilation", compiler_ticks, active); | |
1474 print_ticks("Unknown: vtable stubs", unknown_ticks_array[ut_vtable_stubs], active); | |
1475 print_ticks("Unknown: null method", unknown_ticks_array[ut_null_method], active); | |
1476 print_ticks("Unknown: running frame", unknown_ticks_array[ut_running_frame], active); | |
1477 print_ticks("Unknown: calling frame", unknown_ticks_array[ut_calling_frame], active); | |
1478 print_ticks("Unknown: no pc", unknown_ticks_array[ut_no_pc], active); | |
1479 print_ticks("Unknown: no last frame", unknown_ticks_array[ut_no_last_Java_frame], active); | |
1480 print_ticks("Unknown: thread_state", unknown_ticks_array[ut_unknown_thread_state], active); | |
1481 tty->cr(); | |
1482 } | |
1483 | |
1484 if (WizardMode) { | |
1485 tty->print_cr("Node area used: %dKb", (area_top - area_bottom) / 1024); | |
1486 } | |
1487 reset(); | |
1488 } | |
1489 | |
1490 /* | |
1491 ThreadProfiler::print_unknown(){ | |
1492 if (table == NULL) { | |
1493 return; | |
1494 } | |
1495 | |
1496 if (thread_ticks <= 0) { | |
1497 return; | |
1498 } | |
1499 } */ | |
1500 | |
1501 void FlatProfiler::print(int unused) { | |
1502 ResourceMark rm; | |
1503 if (thread_profiler != NULL) { | |
1504 thread_profiler->print("All threads"); | |
1505 } else { | |
1506 MutexLocker tl(Threads_lock); | |
1507 for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { | |
1508 ThreadProfiler* pp = tp->get_thread_profiler(); | |
1509 if (pp != NULL) { | |
1510 pp->print(tp->get_thread_name()); | |
1511 } | |
1512 } | |
1513 } | |
1514 | |
1515 if (ProfilerPrintByteCodeStatistics) { | |
1516 print_byte_code_statistics(); | |
1517 } | |
1518 | |
1519 if (non_method_ticks() > 0) { | |
1520 tty->cr(); | |
1521 tty->print_cr("Global summary of %3.2f seconds:", timer.seconds()); | |
1522 print_ticks("Received ticks", received_ticks, received_ticks); | |
1523 print_ticks("Received GC ticks", received_gc_ticks, received_ticks); | |
1524 print_ticks("Compilation", compiler_ticks, received_ticks); | |
1525 print_ticks("Deoptimization", deopt_ticks, received_ticks); | |
1526 print_ticks("Other VM operations", vm_operation_ticks, received_ticks); | |
1527 #ifndef PRODUCT | |
1528 print_ticks("Blocked ticks", blocked_ticks, received_ticks); | |
1529 print_ticks("Threads_lock blocks", threads_lock_ticks, received_ticks); | |
1530 print_ticks("Delivered ticks", delivered_ticks, received_ticks); | |
1531 print_ticks("All ticks", all_ticks, received_ticks); | |
1532 #endif | |
1533 print_ticks("Class loader", class_loader_ticks, received_ticks); | |
1534 print_ticks("Extra ", extra_ticks, received_ticks); | |
1535 print_ticks("Interpreter", interpreter_ticks, received_ticks); | |
1536 print_ticks("Unknown code", unknown_ticks, received_ticks); | |
1537 } | |
1538 | |
1539 PCRecorder::print(); | |
1540 | |
1541 if(ProfileVM){ | |
1542 tty->cr(); | |
1543 vm_thread_profiler->print("VM Thread"); | |
1544 } | |
1545 } | |
1546 | |
1547 void IntervalData::print_header(outputStream* st) { | |
1548 st->print("i/c/n/g"); | |
1549 } | |
1550 | |
1551 void IntervalData::print_data(outputStream* st) { | |
1552 st->print("%d/%d/%d/%d", interpreted(), compiled(), native(), compiling()); | |
1553 } | |
1554 | |
1555 void FlatProfiler::interval_record_thread(ThreadProfiler* tp) { | |
1556 IntervalData id = tp->interval_data(); | |
1557 int total = id.total(); | |
1558 tp->interval_data_ref()->reset(); | |
1559 | |
1560 // Insertion sort the data, if it's relevant. | |
1561 for (int i = 0; i < interval_print_size; i += 1) { | |
1562 if (total > interval_data[i].total()) { | |
1563 for (int j = interval_print_size - 1; j > i; j -= 1) { | |
1564 interval_data[j] = interval_data[j-1]; | |
1565 } | |
1566 interval_data[i] = id; | |
1567 break; | |
1568 } | |
1569 } | |
1570 } | |
1571 | |
1572 void FlatProfiler::interval_print() { | |
1573 if ((interval_data[0].total() > 0)) { | |
1574 tty->stamp(); | |
1575 tty->print("\t"); | |
1576 IntervalData::print_header(tty); | |
1577 for (int i = 0; i < interval_print_size; i += 1) { | |
1578 if (interval_data[i].total() > 0) { | |
1579 tty->print("\t"); | |
1580 interval_data[i].print_data(tty); | |
1581 } | |
1582 } | |
1583 tty->cr(); | |
1584 } | |
1585 } | |
1586 | |
1587 void FlatProfiler::interval_reset() { | |
1588 for (int i = 0; i < interval_print_size; i += 1) { | |
1589 interval_data[i].reset(); | |
1590 } | |
1591 } | |
1592 | |
1593 void ThreadProfiler::oops_do(OopClosure* f) { | |
1594 if (table == NULL) return; | |
1595 | |
1596 for(int index = 0; index < table_size; index++) { | |
1597 for(ProfilerNode* node = table[index]; node; node = node->next()) | |
1598 node->oops_do(f); | |
1599 } | |
1600 } | |
1601 | |
1602 void FlatProfiler::oops_do(OopClosure* f) { | |
1603 if (thread_profiler != NULL) { | |
1604 thread_profiler->oops_do(f); | |
1605 } else { | |
1606 for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { | |
1607 ThreadProfiler* pp = tp->get_thread_profiler(); | |
1608 if (pp != NULL) { | |
1609 pp->oops_do(f); | |
1610 } | |
1611 } | |
1612 } | |
1613 } |