1 | /* |
2 | * Copyright (c) 1997, 2010, 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 "interpreter/bytecodeHistogram.hpp" |
27 | #include "memory/resourceArea.hpp" |
28 | #include "runtime/os.hpp" |
29 | #include "utilities/growableArray.hpp" |
30 | |
31 | // ------------------------------------------------------------------------------------------------ |
32 | // Non-product code |
33 | #ifndef PRODUCT |
34 | |
35 | // Implementation of BytecodeCounter |
36 | |
37 | int BytecodeCounter::_counter_value = 0; |
38 | jlong BytecodeCounter::_reset_time = 0; |
39 | |
40 | |
41 | void BytecodeCounter::reset() { |
42 | _counter_value = 0; |
43 | _reset_time = os::elapsed_counter(); |
44 | } |
45 | |
46 | |
47 | double BytecodeCounter::elapsed_time() { |
48 | return (double)(os::elapsed_counter() - _reset_time) / (double)os::elapsed_frequency(); |
49 | } |
50 | |
51 | |
52 | double BytecodeCounter::frequency() { |
53 | return (double)counter_value() / elapsed_time(); |
54 | } |
55 | |
56 | |
57 | void BytecodeCounter::print() { |
58 | tty->print_cr( |
59 | "%d bytecodes executed in %.1fs (%.3fMHz)" , |
60 | counter_value(), |
61 | elapsed_time(), |
62 | frequency() / 1000000.0 |
63 | ); |
64 | } |
65 | |
66 | |
67 | // Helper class for sorting |
68 | |
69 | class HistoEntry: public ResourceObj { |
70 | private: |
71 | int _index; |
72 | int _count; |
73 | |
74 | public: |
75 | HistoEntry(int index, int count) { _index = index; _count = count; } |
76 | int index() const { return _index; } |
77 | int count() const { return _count; } |
78 | |
79 | static int compare(HistoEntry** x, HistoEntry** y) { return (*x)->count() - (*y)->count(); } |
80 | }; |
81 | |
82 | |
83 | // Helper functions |
84 | |
85 | static GrowableArray<HistoEntry*>* sorted_array(int* array, int length) { |
86 | GrowableArray<HistoEntry*>* a = new GrowableArray<HistoEntry*>(length); |
87 | int i = length; |
88 | while (i-- > 0) a->append(new HistoEntry(i, array[i])); |
89 | a->sort(HistoEntry::compare); |
90 | return a; |
91 | } |
92 | |
93 | |
94 | static int total_count(GrowableArray<HistoEntry*>* profile) { |
95 | int sum = 0; |
96 | int i = profile->length(); |
97 | while (i-- > 0) sum += profile->at(i)->count(); |
98 | return sum; |
99 | } |
100 | |
101 | |
102 | static const char* name_for(int i) { |
103 | return Bytecodes::is_defined(i) ? Bytecodes::name(Bytecodes::cast(i)) : "xxxunusedxxx" ; |
104 | } |
105 | |
106 | |
107 | // Implementation of BytecodeHistogram |
108 | |
109 | int BytecodeHistogram::_counters[Bytecodes::number_of_codes]; |
110 | |
111 | |
112 | void BytecodeHistogram::reset() { |
113 | int i = Bytecodes::number_of_codes; |
114 | while (i-- > 0) _counters[i] = 0; |
115 | } |
116 | |
117 | |
118 | void BytecodeHistogram::print(float cutoff) { |
119 | ResourceMark rm; |
120 | GrowableArray<HistoEntry*>* profile = sorted_array(_counters, Bytecodes::number_of_codes); |
121 | // print profile |
122 | int tot = total_count(profile); |
123 | int abs_sum = 0; |
124 | tty->cr(); //0123456789012345678901234567890123456789012345678901234567890123456789 |
125 | tty->print_cr("Histogram of %d executed bytecodes:" , tot); |
126 | tty->cr(); |
127 | tty->print_cr(" absolute relative code name" ); |
128 | tty->print_cr("----------------------------------------------------------------------" ); |
129 | int i = profile->length(); |
130 | while (i-- > 0) { |
131 | HistoEntry* e = profile->at(i); |
132 | int abs = e->count(); |
133 | float rel = abs * 100.0F / tot; |
134 | if (cutoff <= rel) { |
135 | tty->print_cr("%10d %7.2f%% %02x %s" , abs, rel, e->index(), name_for(e->index())); |
136 | abs_sum += abs; |
137 | } |
138 | } |
139 | tty->print_cr("----------------------------------------------------------------------" ); |
140 | float rel_sum = abs_sum * 100.0F / tot; |
141 | tty->print_cr("%10d %7.2f%% (cutoff = %.2f%%)" , abs_sum, rel_sum, cutoff); |
142 | tty->cr(); |
143 | } |
144 | |
145 | |
146 | // Implementation of BytecodePairHistogram |
147 | |
148 | int BytecodePairHistogram::_index; |
149 | int BytecodePairHistogram::_counters[BytecodePairHistogram::number_of_pairs]; |
150 | |
151 | |
152 | void BytecodePairHistogram::reset() { |
153 | _index = Bytecodes::_nop << log2_number_of_codes; |
154 | |
155 | int i = number_of_pairs; |
156 | while (i-- > 0) _counters[i] = 0; |
157 | } |
158 | |
159 | |
160 | void BytecodePairHistogram::print(float cutoff) { |
161 | ResourceMark rm; |
162 | GrowableArray<HistoEntry*>* profile = sorted_array(_counters, number_of_pairs); |
163 | // print profile |
164 | int tot = total_count(profile); |
165 | int abs_sum = 0; |
166 | tty->cr(); //0123456789012345678901234567890123456789012345678901234567890123456789 |
167 | tty->print_cr("Histogram of %d executed bytecode pairs:" , tot); |
168 | tty->cr(); |
169 | tty->print_cr(" absolute relative codes 1st bytecode 2nd bytecode" ); |
170 | tty->print_cr("----------------------------------------------------------------------" ); |
171 | int i = profile->length(); |
172 | while (i-- > 0) { |
173 | HistoEntry* e = profile->at(i); |
174 | int abs = e->count(); |
175 | float rel = abs * 100.0F / tot; |
176 | if (cutoff <= rel) { |
177 | int c1 = e->index() % number_of_codes; |
178 | int c2 = e->index() / number_of_codes; |
179 | tty->print_cr("%10d %6.3f%% %02x %02x %-19s %s" , abs, rel, c1, c2, name_for(c1), name_for(c2)); |
180 | abs_sum += abs; |
181 | } |
182 | } |
183 | tty->print_cr("----------------------------------------------------------------------" ); |
184 | float rel_sum = abs_sum * 100.0F / tot; |
185 | tty->print_cr("%10d %6.3f%% (cutoff = %.3f%%)" , abs_sum, rel_sum, cutoff); |
186 | tty->cr(); |
187 | } |
188 | |
189 | #endif |
190 | |