Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / vprof / vprof.cpp
1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is Value-Profiling Utility.
16  *
17  * The Initial Developer of the Original Code is
18  * Intel Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 2008
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *   Mohammad R. Haghighat [mohammad.r.haghighat@intel.com] 
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either the GNU General Public License Version 2 or later (the "GPL"), or
27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK ***** */
38
39 #include "VMPI.h"
40
41 // Note, this is not supported in configurations with more than one AvmCore running
42 // in the same process.
43
44 #ifdef WIN32
45 #include "windows.h"
46 #else
47 #define __cdecl
48 #include <stdarg.h>
49 #include <string.h>
50 #endif
51
52 #include "vprof.h"
53
54 #define MIN(x,y) ((x) <= (y) ? x : y)
55 #define MAX(x,y) ((x) >= (y) ? x : y)
56
57 #ifndef MAXINT
58 #define MAXINT int(unsigned(-1)>>1)
59 #endif
60
61 #ifndef MAXINT64
62 #define MAXINT64 int64_t(uint64_t(-1)>>1)
63 #endif
64
65 #ifndef __STDC_WANT_SECURE_LIB__
66 #define sprintf_s(b,size,fmt,...) sprintf((b),(fmt),__VA_ARGS__)
67 #endif
68
69 #if THREADED
70 #define DO_LOCK(lock) Lock(lock); {
71 #define DO_UNLOCK(lock) }; Unlock(lock)
72 #else
73 #define DO_LOCK(lock) { (void)(lock);
74 #define DO_UNLOCK(lock) }
75 #endif
76
77 #if THREAD_SAFE  
78 #define LOCK(lock) DO_LOCK(lock)
79 #define UNLOCK(lock) DO_UNLOCK(lock)
80 #else
81 #define LOCK(lock) { (void)(lock);
82 #define UNLOCK(lock) }
83 #endif
84
85 static entry* entries = NULL;
86 static bool notInitialized = true;
87 static long glock = LOCK_IS_FREE;
88
89 #define Lock(lock) while (_InterlockedCompareExchange(lock, LOCK_IS_TAKEN, LOCK_IS_FREE) == LOCK_IS_TAKEN){};
90 #define Unlock(lock) _InterlockedCompareExchange(lock, LOCK_IS_FREE, LOCK_IS_TAKEN);
91
92 #if defined(WIN32) && !defined(UNDER_CE)
93         static void vprof_printf(const char* format, ...)
94         {
95                 va_list args;
96                 va_start(args, format);
97
98                 char buf[1024];
99                 vsnprintf(buf, sizeof(buf), format, args);
100                 
101                 va_end(args);
102
103                 printf(buf);
104                 ::OutputDebugStringA(buf);
105         }
106 #else
107         #define vprof_printf printf
108 #endif
109
110 inline static entry* reverse (entry* s)
111 {
112     entry_t e, n, p;
113
114     p = NULL;
115     for (e = s; e; e = n) {
116         n = e->next;
117         e->next = p;
118         p = e;
119     }
120     
121     return p;
122 }
123
124 static char* f (double d)
125 {
126     static char s[80];
127     char* p;
128     sprintf_s (s, sizeof(s), "%lf", d);
129     p = s+VMPI_strlen(s)-1;
130     while (*p == '0') {
131         *p = '\0';
132         p--;
133         if (p == s) break;
134     }
135     if (*p == '.') *p = '\0';
136     return s;
137 }
138
139 static void dumpProfile (void)
140 {
141     entry_t e;
142
143     entries = reverse(entries);
144     vprof_printf ("event avg [min : max] total count\n");
145     for (e = entries; e; e = e->next) {
146         if (e->count == 0) continue;  // ignore entries with zero count.
147         vprof_printf ("%s", e->file); 
148         if (e->line >= 0) {
149             vprof_printf (":%d", e->line);
150         } 
151         vprof_printf (" %s [%lld : %lld] %lld %lld ", 
152                 f(((double)e->sum)/((double)e->count)), (long long int)e->min, (long long int)e->max, (long long int)e->sum, (long long int)e->count);
153         if (e->h) {
154             int j = MAXINT;
155             for (j = 0; j < e->h->nbins; j ++) {
156                 vprof_printf ("(%lld < %lld) ", (long long int)e->h->count[j], (long long int)e->h->lb[j]);
157             }
158             vprof_printf ("(%lld >= %lld) ", (long long int)e->h->count[e->h->nbins], (long long int)e->h->lb[e->h->nbins-1]);
159         }
160         if (e->func) {
161             int j;
162             for (j = 0; j < NUM_EVARS; j++) {
163                 if (e->ivar[j] != 0) {
164                     vprof_printf ("IVAR%d %d ", j, e->ivar[j]);
165                 }
166             }
167             for (j = 0; j < NUM_EVARS; j++) {
168                 if (e->i64var[j] != 0) {
169                     vprof_printf ("I64VAR%d %lld ", j, (long long int)e->i64var[j]);
170                 }
171             }
172             for (j = 0; j < NUM_EVARS; j++) {
173                 if (e->dvar[j] != 0) {
174                     vprof_printf ("DVAR%d %lf ", j, e->dvar[j]);
175                 }
176             }
177         }
178         vprof_printf ("\n");
179     }
180     entries = reverse(entries);
181 }
182
183 inline static entry_t findEntry (char* file, int line)
184 {
185     for (entry_t e =  entries; e; e = e->next) {
186         if ((e->line == line) && (VMPI_strcmp (e->file, file) == 0)) {
187             return e;
188         }
189     }
190     return NULL;
191 }
192
193 // Initialize the location pointed to by 'id' to a new value profile entry
194 // associated with 'file' and 'line', or do nothing if already initialized.
195 // An optional final argument provides a user-defined probe function.
196
197 int initValueProfile(void** id, char* file, int line, ...)
198 {
199     DO_LOCK (&glock);
200         entry_t e = (entry_t) *id;
201         if (notInitialized) {
202             atexit (dumpProfile);
203             notInitialized = false;
204         }
205
206         if (e == NULL) {
207             e = findEntry (file, line);
208             if (e) {
209                 *id = e;
210             }
211         }
212
213         if (e == NULL) {
214             va_list va;
215             e = (entry_t) malloc (sizeof(entry));
216             e->lock = LOCK_IS_FREE;
217             e->file = file;
218             e->line = line;
219             e->value = 0;
220             e->sum = 0;
221             e->count = 0;
222             e->min = 0;
223             e->max = 0;
224             // optional probe function argument
225             va_start (va, line);
226             e->func = (void (__cdecl*)(void*)) va_arg (va, void*);
227             va_end (va);
228             e->h = NULL;
229             e->genptr = NULL;
230             VMPI_memset (&e->ivar,   0, sizeof(e->ivar));
231             VMPI_memset (&e->i64var, 0, sizeof(e->i64var));
232             VMPI_memset (&e->dvar,   0, sizeof(e->dvar));
233             e->next = entries;
234             entries = e;
235             *id = e;
236         }
237     DO_UNLOCK (&glock);
238
239     return 0;
240 }
241
242 // Record a value profile event.
243
244 int profileValue(void* id, int64_t value)
245 {
246     entry_t e = (entry_t) id;
247     long* lock = &(e->lock);
248     LOCK (lock);
249         e->value = value;
250         if (e->count == 0) {
251             e->sum = value;
252             e->count = 1;
253             e->min = value;
254             e->max = value;
255         } else {
256             e->sum += value;
257             e->count ++;
258             e->min = MIN (e->min, value);
259             e->max = MAX (e->max, value);
260         }
261         if (e->func) e->func (e);
262     UNLOCK (lock);
263
264     return 0;
265 }
266
267 // Initialize the location pointed to by 'id' to a new histogram profile entry
268 // associated with 'file' and 'line', or do nothing if already initialized.
269
270 int initHistProfile(void** id, char* file, int line, int nbins, ...)
271 {
272     DO_LOCK (&glock);
273         entry_t e = (entry_t) *id;
274         if (notInitialized) {
275             atexit (dumpProfile);
276             notInitialized = false;
277         }
278
279         if (e == NULL) {
280             e = findEntry (file, line);
281             if (e) {
282                 *id = e;
283             }
284         } 
285
286         if (e == NULL) {
287             va_list va;
288             hist_t h;
289             int b, n, s;
290             int64_t* lb;
291
292             e = (entry_t) malloc (sizeof(entry));
293             e->lock = LOCK_IS_FREE;
294             e->file = file;
295             e->line = line;
296             e->value = 0;
297             e->sum = 0;
298             e->count = 0;
299             e->min = 0;
300             e->max = 0;
301             e->func = NULL;
302             e->h = h = (hist_t) malloc (sizeof(hist));
303             n = 1+MAX(nbins,0);
304             h->nbins = n-1;
305             s = n*sizeof(int64_t);
306             lb = (int64_t*) malloc (s);
307             h->lb = lb;
308             VMPI_memset (h->lb, 0, s);
309             h->count = (int64_t*) malloc (s);
310             VMPI_memset (h->count, 0, s);
311
312             va_start (va, nbins);
313             for (b = 0; b < nbins; b++) {
314                 //lb[b] = va_arg (va, int64_t);
315                 lb[b] = va_arg (va, int);
316             }
317             lb[b] = MAXINT64;
318             va_end (va);
319
320             e->genptr = NULL;
321             VMPI_memset (&e->ivar,   0, sizeof(e->ivar));
322             VMPI_memset (&e->i64var, 0, sizeof(e->i64var));
323             VMPI_memset (&e->dvar,   0, sizeof(e->dvar));
324             e->next = entries;
325             entries = e;
326             *id = e;
327         }
328     DO_UNLOCK (&glock);
329
330     return 0;
331 }
332
333 // Record a histogram profile event.
334
335 int histValue(void* id, int64_t value)
336 {
337     entry_t e = (entry_t) id;
338     long* lock = &(e->lock);
339     hist_t h = e->h;
340     int nbins = h->nbins;
341     int64_t* lb = h->lb;
342     int b;
343
344     LOCK (lock);
345         e->value = value;
346         if (e->count == 0) {
347             e->sum = value;
348             e->count = 1;
349             e->min = value;
350             e->max = value;
351         } else {
352             e->sum += value;
353             e->count ++;
354             e->min = MIN (e->min, value);
355             e->max = MAX (e->max, value);
356         }
357         for (b = 0; b < nbins; b ++) {
358             if (value < lb[b]) break;
359         }
360         h->count[b] ++;
361     UNLOCK (lock);
362
363     return 0;
364 }
365
366 #if defined(_MSC_VER) && defined(_M_IX86)
367 uint64_t readTimestampCounter()
368 {
369         // read the cpu cycle counter.  1 tick = 1 cycle on IA32
370         _asm rdtsc;
371 }
372 #elif defined(__GNUC__) && (__i386__ || __x86_64__)
373 uint64_t readTimestampCounter()
374 {
375    uint32_t lo, hi;
376    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
377    return (uint64_t(hi) << 32) | lo;
378 }
379 #else
380 // add stub for platforms without it, so fat builds don't fail
381 uint64_t readTimestampCounter() { return 0; }
382 #endif
383