Method call frequency statistics for ARM
[cacao.git] / src / vm / jit / optimizing / profile.cpp
1 /* src/vm/jit/optimizing/profile.cpp - runtime profiling
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008, 2009
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5    Copyright (C) 2009 Theobroma Systems Ltd.
6
7    This file is part of CACAO.
8
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2, or (at
12    your option) any later version.
13
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22    02110-1301, USA.
23
24 */
25
26
27 #include "config.h"
28
29 #include <assert.h>
30 #include <stdlib.h>
31
32 #include "vm/types.h"
33
34 #include "mm/memory.hpp"
35
36 #include "threads/threadlist.hpp"
37 #include "threads/thread.hpp"
38
39 #include "vm/jit/builtin.hpp"
40 #include "vm/class.hpp"
41 #include "vm/classcache.hpp"
42 #include "vm/method.hpp"
43 #include "vm/options.h"
44 #include "vm/string.hpp"
45
46 #include "vm/jit/jit.hpp"
47 #include "vm/jit/methodheader.h"
48 #include "vm/jit/methodtree.h"
49
50 #include "vm/jit/optimizing/recompiler.hpp"
51
52
53 /* profile_init ****************************************************************
54
55    Initializes the profile global lock.
56
57 *******************************************************************************/
58
59 bool profile_init(void)
60 {
61         /* everything's ok */
62
63         return true;
64 }
65
66
67 /* profile_thread **************************************************************
68
69    XXX
70
71 *******************************************************************************/
72
73 static s4 runs = 0;
74 static s4 hits = 0;
75 static s4 misses = 0;
76
77 #if defined(ENABLE_THREADS)
78 static void profile_thread(void)
79 {
80         threadobject *t;
81         s4            nanos;
82         u1           *pc;
83         u1           *pv;
84         methodinfo   *m;
85         codeinfo     *code;
86
87         while (true) {
88                 /* sleep thread for 0.5-1.0 ms */
89
90                 nanos = 500 + (int) (500.0 * (rand() / (RAND_MAX + 1.0)));
91 /*              fprintf(stderr, "%d\n", nanos); */
92
93                 threads_sleep(0, nanos);
94                 runs++;
95
96                 // Lock the thread lists.
97                 ThreadList::lock();
98
99 #if 0
100                 /* iterate over all started threads */
101
102                 for (t = ThreadList_first(); t != NULL; t = ThreadList_next(t)) {
103                         /* is this a Java thread? */
104
105                         if (!(t->flags & THREAD_FLAG_JAVA))
106                                 continue;
107
108                         /* send SIGUSR2 to thread to get the current PC */
109                         /* XXX write a threads-function for that */
110
111                         pthread_kill(t->tid, SIGUSR2);
112
113                         /* the thread object now contains the current thread PC */
114
115                         pc = t->pc;
116
117                         /* Get the PV for the current PC. */
118
119                         pv = methodtree_find_nocheck(pc);
120
121                         /* get methodinfo pointer from data segment */
122
123                         if (pv == NULL) {
124                                 misses++;
125                         }
126                         else {
127                                 code = *((codeinfo **) (pv + CodeinfoPointer));
128
129                                 /* For asm_vm_call_method the codeinfo pointer is NULL
130                                    (which is also in the method tree). */
131
132                                 if (code != NULL) {
133                                         m = code->m;
134
135                                         /* native methods are never recompiled */
136
137                                         if (!(m->flags & ACC_NATIVE)) {
138                                                 /* increase the method incovation counter */
139
140                                                 code->frequency++;
141                                                 hits++;
142
143                                                 if (code->frequency > 500) {
144                                                         /* clear frequency count before
145                                                            recompilation */
146
147                                                         code->frequency = 0;
148
149                                                         /* add this method to the method list and
150                                                            start recompilation */
151
152                                                         Recompiler_queue_method(m);
153                                                 }
154                                         }
155                                 }
156                         }
157                 }
158 #endif
159
160                 // Unlock the thread lists.
161                 ThreadList::unlock();
162         }
163 }
164 #endif
165
166
167 /* profile_start_thread ********************************************************
168
169    Starts the profile sampling thread.
170
171 *******************************************************************************/
172
173 #if defined(ENABLE_THREADS)
174 bool profile_start_thread(void)
175 {
176         utf *name;
177
178         name = utf_new_char("Profiling Sampler");
179
180         if (!threads_thread_start_internal(name, profile_thread))
181                 return false;
182
183         /* everything's ok */
184
185         return true;
186 }
187 #endif
188
189
190 /**
191  * Comparison function used to sort a method list from higher to lower by
192  * comparing the method call frequencies.
193  *
194  * @param m1 First method to be compared.
195  * @param m2 Second method to be compared.
196  * @return Returns true if the first method goes before the second method in
197  * the specific order, and false otherwise.
198  */
199 #if !defined(NDEBUG)
200 static bool profile_compare_frequency(methodinfo* m1, methodinfo* m2)
201 {
202         return (m1->code->frequency > m2->code->frequency);
203 }
204 #endif
205
206
207 /**
208  * Prints profiling statistics gathered during runtime.
209  */
210 #if !defined(NDEBUG)
211 void profile_printstats(void)
212 {
213         classinfo              *c;
214         methodinfo             *m;
215         codeinfo               *code;
216         u4                      slot;
217         classcache_name_entry  *nmen;
218         classcache_class_entry *clsen;
219         s4                      i;
220         s4                      j;
221         u4                      frequency;
222         s8                      cycles;
223
224         frequency = 0;
225         cycles    = 0;
226
227         /* create new method list */
228
229         std::list<methodinfo*> l;
230         //DumpList<methodinfo*> l; // XXX currently the DumpList doesn't work here.
231
232         /* iterate through all classes and methods */
233
234         for (slot = 0; slot < hashtable_classcache.size; slot++) {
235                 nmen = (classcache_name_entry *) hashtable_classcache.ptr[slot];
236
237                 for (; nmen; nmen = nmen->hashlink) {
238                         /* iterate over all class entries */
239
240                         for (clsen = nmen->classes; clsen; clsen = clsen->next) {
241                                 c = clsen->classobj;
242
243                                 if (c == NULL)
244                                         continue;
245
246                                 /* interate over all class methods */
247
248                                 for (i = 0; i < c->methodscount; i++) {
249                                         m = &(c->methods[i]);
250
251                                         code = m->code;
252
253                                         /* was this method actually called? */
254
255                                         if ((code != NULL) && (code->frequency > 0)) {
256                                                 /* add to overall stats */
257
258                                                 frequency += code->frequency;
259                                                 cycles    += code->cycles;
260
261                                                 /* add new entry into method list */
262
263                                                 l.push_back(m);
264                                         }
265                                 }
266                         }
267                 }
268         }
269
270         /* sort the method list */
271
272         l.sort(profile_compare_frequency);
273
274         /* print all methods sorted */
275
276         printf(" frequency     ratio         cycles     ratio   method name\n");
277         printf("----------- --------- -------------- --------- -------------\n");
278
279         /* now iterate through the list and print it */
280
281         for (DumpList<methodinfo*>::iterator it = l.begin(); it != l.end(); ++it) {
282                 m = *(it);
283
284                 code = m->code;
285
286                 printf("%10d   %.5f   %12ld   %.5f   ",
287                            code->frequency,
288                            (double) code->frequency / (double) frequency,
289                            (long) code->cycles,
290                            (double) code->cycles / (double) cycles);
291
292                 method_println(m);
293
294                 /* print basic block frequencies */
295
296                 if (opt_prof_bb) {
297                         for (j = 0; j < code->basicblockcount; j++)
298                                 printf("                                                    L%03d: %10d\n",
299                                            j, code->bbfrequency[j]);
300                 }
301         }
302
303         printf("-----------           -------------- \n");
304         printf("%10d             %12ld\n", frequency, (long) cycles);
305
306         printf("\nruns  : %10d\n", runs);
307         printf("hits  : %10d\n", hits);
308         printf("misses: %10d\n", misses);
309 }
310 #endif /* !defined(NDEBUG) */
311
312
313 /*
314  * These are local overrides for various environment variables in Emacs.
315  * Please do not remove this and leave it at the end of the file, where
316  * Emacs will automagically detect them.
317  * ---------------------------------------------------------------------
318  * Local variables:
319  * mode: c++
320  * indent-tabs-mode: t
321  * c-basic-offset: 4
322  * tab-width: 4
323  * End:
324  */