Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "VMPI.h" |
michael@0 | 7 | |
michael@0 | 8 | // Note, this is not supported in configurations with more than one AvmCore running |
michael@0 | 9 | // in the same process. |
michael@0 | 10 | |
michael@0 | 11 | #ifdef WIN32 |
michael@0 | 12 | #include "windows.h" |
michael@0 | 13 | #else |
michael@0 | 14 | #define __cdecl |
michael@0 | 15 | #include <stdarg.h> |
michael@0 | 16 | #include <string.h> |
michael@0 | 17 | #endif |
michael@0 | 18 | |
michael@0 | 19 | #include "vprof.h" |
michael@0 | 20 | |
michael@0 | 21 | #ifndef MIN |
michael@0 | 22 | #define MIN(x,y) ((x) <= (y) ? x : y) |
michael@0 | 23 | #endif |
michael@0 | 24 | #ifndef MAX |
michael@0 | 25 | #define MAX(x,y) ((x) >= (y) ? x : y) |
michael@0 | 26 | #endif |
michael@0 | 27 | |
michael@0 | 28 | #ifndef MAXINT |
michael@0 | 29 | #define MAXINT int(unsigned(-1)>>1) |
michael@0 | 30 | #endif |
michael@0 | 31 | |
michael@0 | 32 | #ifndef MAXINT64 |
michael@0 | 33 | #define MAXINT64 int64_t(uint64_t(-1)>>1) |
michael@0 | 34 | #endif |
michael@0 | 35 | |
michael@0 | 36 | #ifndef __STDC_WANT_SECURE_LIB__ |
michael@0 | 37 | #define sprintf_s(b,size,fmt,...) sprintf((b),(fmt),__VA_ARGS__) |
michael@0 | 38 | #endif |
michael@0 | 39 | |
michael@0 | 40 | #if THREADED |
michael@0 | 41 | #define DO_LOCK(lock) Lock(lock); { |
michael@0 | 42 | #define DO_UNLOCK(lock) }; Unlock(lock) |
michael@0 | 43 | #else |
michael@0 | 44 | #define DO_LOCK(lock) { (void)(lock); |
michael@0 | 45 | #define DO_UNLOCK(lock) } |
michael@0 | 46 | #endif |
michael@0 | 47 | |
michael@0 | 48 | #if THREAD_SAFE |
michael@0 | 49 | #define LOCK(lock) DO_LOCK(lock) |
michael@0 | 50 | #define UNLOCK(lock) DO_UNLOCK(lock) |
michael@0 | 51 | #else |
michael@0 | 52 | #define LOCK(lock) { (void)(lock); |
michael@0 | 53 | #define UNLOCK(lock) } |
michael@0 | 54 | #endif |
michael@0 | 55 | |
michael@0 | 56 | static entry* entries = nullptr; |
michael@0 | 57 | static bool notInitialized = true; |
michael@0 | 58 | static long glock = LOCK_IS_FREE; |
michael@0 | 59 | |
michael@0 | 60 | #define Lock(lock) while (_InterlockedCompareExchange(lock, LOCK_IS_TAKEN, LOCK_IS_FREE) == LOCK_IS_TAKEN){}; |
michael@0 | 61 | #define Unlock(lock) _InterlockedCompareExchange(lock, LOCK_IS_FREE, LOCK_IS_TAKEN); |
michael@0 | 62 | |
michael@0 | 63 | #if defined(WIN32) |
michael@0 | 64 | static void vprof_printf(const char* format, ...) |
michael@0 | 65 | { |
michael@0 | 66 | va_list args; |
michael@0 | 67 | va_start(args, format); |
michael@0 | 68 | |
michael@0 | 69 | char buf[1024]; |
michael@0 | 70 | vsnprintf(buf, sizeof(buf), format, args); |
michael@0 | 71 | |
michael@0 | 72 | va_end(args); |
michael@0 | 73 | |
michael@0 | 74 | printf(buf); |
michael@0 | 75 | ::OutputDebugStringA(buf); |
michael@0 | 76 | } |
michael@0 | 77 | #else |
michael@0 | 78 | #define vprof_printf printf |
michael@0 | 79 | #endif |
michael@0 | 80 | |
michael@0 | 81 | static inline entry* reverse (entry* s) |
michael@0 | 82 | { |
michael@0 | 83 | entry_t e, n, p; |
michael@0 | 84 | |
michael@0 | 85 | p = nullptr; |
michael@0 | 86 | for (e = s; e; e = n) { |
michael@0 | 87 | n = e->next; |
michael@0 | 88 | e->next = p; |
michael@0 | 89 | p = e; |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | return p; |
michael@0 | 93 | } |
michael@0 | 94 | |
michael@0 | 95 | static char* f (double d) |
michael@0 | 96 | { |
michael@0 | 97 | static char s[80]; |
michael@0 | 98 | char* p; |
michael@0 | 99 | sprintf_s (s, sizeof(s), "%lf", d); |
michael@0 | 100 | p = s+VMPI_strlen(s)-1; |
michael@0 | 101 | while (*p == '0') { |
michael@0 | 102 | *p = '\0'; |
michael@0 | 103 | p--; |
michael@0 | 104 | if (p == s) break; |
michael@0 | 105 | } |
michael@0 | 106 | if (*p == '.') *p = '\0'; |
michael@0 | 107 | return s; |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | static void dumpProfile (void) |
michael@0 | 111 | { |
michael@0 | 112 | entry_t e; |
michael@0 | 113 | |
michael@0 | 114 | entries = reverse(entries); |
michael@0 | 115 | vprof_printf ("event avg [min : max] total count\n"); |
michael@0 | 116 | for (e = entries; e; e = e->next) { |
michael@0 | 117 | if (e->count == 0) continue; // ignore entries with zero count. |
michael@0 | 118 | vprof_printf ("%s", e->file); |
michael@0 | 119 | if (e->line >= 0) { |
michael@0 | 120 | vprof_printf (":%d", e->line); |
michael@0 | 121 | } |
michael@0 | 122 | vprof_printf (" %s [%lld : %lld] %lld %lld ", |
michael@0 | 123 | 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); |
michael@0 | 124 | if (e->h) { |
michael@0 | 125 | int j = MAXINT; |
michael@0 | 126 | for (j = 0; j < e->h->nbins; j ++) { |
michael@0 | 127 | vprof_printf ("(%lld < %lld) ", (long long int)e->h->count[j], (long long int)e->h->lb[j]); |
michael@0 | 128 | } |
michael@0 | 129 | vprof_printf ("(%lld >= %lld) ", (long long int)e->h->count[e->h->nbins], (long long int)e->h->lb[e->h->nbins-1]); |
michael@0 | 130 | } |
michael@0 | 131 | if (e->func) { |
michael@0 | 132 | int j; |
michael@0 | 133 | for (j = 0; j < NUM_EVARS; j++) { |
michael@0 | 134 | if (e->ivar[j] != 0) { |
michael@0 | 135 | vprof_printf ("IVAR%d %d ", j, e->ivar[j]); |
michael@0 | 136 | } |
michael@0 | 137 | } |
michael@0 | 138 | for (j = 0; j < NUM_EVARS; j++) { |
michael@0 | 139 | if (e->i64var[j] != 0) { |
michael@0 | 140 | vprof_printf ("I64VAR%d %lld ", j, (long long int)e->i64var[j]); |
michael@0 | 141 | } |
michael@0 | 142 | } |
michael@0 | 143 | for (j = 0; j < NUM_EVARS; j++) { |
michael@0 | 144 | if (e->dvar[j] != 0) { |
michael@0 | 145 | vprof_printf ("DVAR%d %lf ", j, e->dvar[j]); |
michael@0 | 146 | } |
michael@0 | 147 | } |
michael@0 | 148 | } |
michael@0 | 149 | vprof_printf ("\n"); |
michael@0 | 150 | } |
michael@0 | 151 | entries = reverse(entries); |
michael@0 | 152 | } |
michael@0 | 153 | |
michael@0 | 154 | static inline entry_t findEntry (char* file, int line) |
michael@0 | 155 | { |
michael@0 | 156 | for (entry_t e = entries; e; e = e->next) { |
michael@0 | 157 | if ((e->line == line) && (VMPI_strcmp (e->file, file) == 0)) { |
michael@0 | 158 | return e; |
michael@0 | 159 | } |
michael@0 | 160 | } |
michael@0 | 161 | return nullptr; |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | // Initialize the location pointed to by 'id' to a new value profile entry |
michael@0 | 165 | // associated with 'file' and 'line', or do nothing if already initialized. |
michael@0 | 166 | // An optional final argument provides a user-defined probe function. |
michael@0 | 167 | |
michael@0 | 168 | int initValueProfile(void** id, char* file, int line, ...) |
michael@0 | 169 | { |
michael@0 | 170 | DO_LOCK (&glock); |
michael@0 | 171 | entry_t e = (entry_t) *id; |
michael@0 | 172 | if (notInitialized) { |
michael@0 | 173 | atexit (dumpProfile); |
michael@0 | 174 | notInitialized = false; |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | if (e == nullptr) { |
michael@0 | 178 | e = findEntry (file, line); |
michael@0 | 179 | if (e) { |
michael@0 | 180 | *id = e; |
michael@0 | 181 | } |
michael@0 | 182 | } |
michael@0 | 183 | |
michael@0 | 184 | if (e == nullptr) { |
michael@0 | 185 | va_list va; |
michael@0 | 186 | e = (entry_t) malloc (sizeof(entry)); |
michael@0 | 187 | e->lock = LOCK_IS_FREE; |
michael@0 | 188 | e->file = file; |
michael@0 | 189 | e->line = line; |
michael@0 | 190 | e->value = 0; |
michael@0 | 191 | e->sum = 0; |
michael@0 | 192 | e->count = 0; |
michael@0 | 193 | e->min = 0; |
michael@0 | 194 | e->max = 0; |
michael@0 | 195 | // optional probe function argument |
michael@0 | 196 | va_start (va, line); |
michael@0 | 197 | e->func = (void (__cdecl*)(void*)) va_arg (va, void*); |
michael@0 | 198 | va_end (va); |
michael@0 | 199 | e->h = nullptr; |
michael@0 | 200 | e->genptr = nullptr; |
michael@0 | 201 | VMPI_memset (&e->ivar, 0, sizeof(e->ivar)); |
michael@0 | 202 | VMPI_memset (&e->i64var, 0, sizeof(e->i64var)); |
michael@0 | 203 | VMPI_memset (&e->dvar, 0, sizeof(e->dvar)); |
michael@0 | 204 | e->next = entries; |
michael@0 | 205 | entries = e; |
michael@0 | 206 | *id = e; |
michael@0 | 207 | } |
michael@0 | 208 | DO_UNLOCK (&glock); |
michael@0 | 209 | |
michael@0 | 210 | return 0; |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | // Record a value profile event. |
michael@0 | 214 | |
michael@0 | 215 | int profileValue(void* id, int64_t value) |
michael@0 | 216 | { |
michael@0 | 217 | entry_t e = (entry_t) id; |
michael@0 | 218 | long* lock = &(e->lock); |
michael@0 | 219 | LOCK (lock); |
michael@0 | 220 | e->value = value; |
michael@0 | 221 | if (e->count == 0) { |
michael@0 | 222 | e->sum = value; |
michael@0 | 223 | e->count = 1; |
michael@0 | 224 | e->min = value; |
michael@0 | 225 | e->max = value; |
michael@0 | 226 | } else { |
michael@0 | 227 | e->sum += value; |
michael@0 | 228 | e->count ++; |
michael@0 | 229 | e->min = MIN (e->min, value); |
michael@0 | 230 | e->max = MAX (e->max, value); |
michael@0 | 231 | } |
michael@0 | 232 | if (e->func) e->func (e); |
michael@0 | 233 | UNLOCK (lock); |
michael@0 | 234 | |
michael@0 | 235 | return 0; |
michael@0 | 236 | } |
michael@0 | 237 | |
michael@0 | 238 | // Initialize the location pointed to by 'id' to a new histogram profile entry |
michael@0 | 239 | // associated with 'file' and 'line', or do nothing if already initialized. |
michael@0 | 240 | |
michael@0 | 241 | int initHistProfile(void** id, char* file, int line, int nbins, ...) |
michael@0 | 242 | { |
michael@0 | 243 | DO_LOCK (&glock); |
michael@0 | 244 | entry_t e = (entry_t) *id; |
michael@0 | 245 | if (notInitialized) { |
michael@0 | 246 | atexit (dumpProfile); |
michael@0 | 247 | notInitialized = false; |
michael@0 | 248 | } |
michael@0 | 249 | |
michael@0 | 250 | if (e == nullptr) { |
michael@0 | 251 | e = findEntry (file, line); |
michael@0 | 252 | if (e) { |
michael@0 | 253 | *id = e; |
michael@0 | 254 | } |
michael@0 | 255 | } |
michael@0 | 256 | |
michael@0 | 257 | if (e == nullptr) { |
michael@0 | 258 | va_list va; |
michael@0 | 259 | hist_t h; |
michael@0 | 260 | int b, n, s; |
michael@0 | 261 | int64_t* lb; |
michael@0 | 262 | |
michael@0 | 263 | e = (entry_t) malloc (sizeof(entry)); |
michael@0 | 264 | e->lock = LOCK_IS_FREE; |
michael@0 | 265 | e->file = file; |
michael@0 | 266 | e->line = line; |
michael@0 | 267 | e->value = 0; |
michael@0 | 268 | e->sum = 0; |
michael@0 | 269 | e->count = 0; |
michael@0 | 270 | e->min = 0; |
michael@0 | 271 | e->max = 0; |
michael@0 | 272 | e->func = nullptr; |
michael@0 | 273 | e->h = h = (hist_t) malloc (sizeof(hist)); |
michael@0 | 274 | n = 1+MAX(nbins,0); |
michael@0 | 275 | h->nbins = n-1; |
michael@0 | 276 | s = n*sizeof(int64_t); |
michael@0 | 277 | lb = (int64_t*) malloc (s); |
michael@0 | 278 | h->lb = lb; |
michael@0 | 279 | VMPI_memset (h->lb, 0, s); |
michael@0 | 280 | h->count = (int64_t*) malloc (s); |
michael@0 | 281 | VMPI_memset (h->count, 0, s); |
michael@0 | 282 | |
michael@0 | 283 | va_start (va, nbins); |
michael@0 | 284 | for (b = 0; b < nbins; b++) { |
michael@0 | 285 | //lb[b] = va_arg (va, int64_t); |
michael@0 | 286 | lb[b] = va_arg (va, int); |
michael@0 | 287 | } |
michael@0 | 288 | lb[b] = MAXINT64; |
michael@0 | 289 | va_end (va); |
michael@0 | 290 | |
michael@0 | 291 | e->genptr = nullptr; |
michael@0 | 292 | VMPI_memset (&e->ivar, 0, sizeof(e->ivar)); |
michael@0 | 293 | VMPI_memset (&e->i64var, 0, sizeof(e->i64var)); |
michael@0 | 294 | VMPI_memset (&e->dvar, 0, sizeof(e->dvar)); |
michael@0 | 295 | e->next = entries; |
michael@0 | 296 | entries = e; |
michael@0 | 297 | *id = e; |
michael@0 | 298 | } |
michael@0 | 299 | DO_UNLOCK (&glock); |
michael@0 | 300 | |
michael@0 | 301 | return 0; |
michael@0 | 302 | } |
michael@0 | 303 | |
michael@0 | 304 | // Record a histogram profile event. |
michael@0 | 305 | |
michael@0 | 306 | int histValue(void* id, int64_t value) |
michael@0 | 307 | { |
michael@0 | 308 | entry_t e = (entry_t) id; |
michael@0 | 309 | long* lock = &(e->lock); |
michael@0 | 310 | hist_t h = e->h; |
michael@0 | 311 | int nbins = h->nbins; |
michael@0 | 312 | int64_t* lb = h->lb; |
michael@0 | 313 | int b; |
michael@0 | 314 | |
michael@0 | 315 | LOCK (lock); |
michael@0 | 316 | e->value = value; |
michael@0 | 317 | if (e->count == 0) { |
michael@0 | 318 | e->sum = value; |
michael@0 | 319 | e->count = 1; |
michael@0 | 320 | e->min = value; |
michael@0 | 321 | e->max = value; |
michael@0 | 322 | } else { |
michael@0 | 323 | e->sum += value; |
michael@0 | 324 | e->count ++; |
michael@0 | 325 | e->min = MIN (e->min, value); |
michael@0 | 326 | e->max = MAX (e->max, value); |
michael@0 | 327 | } |
michael@0 | 328 | for (b = 0; b < nbins; b ++) { |
michael@0 | 329 | if (value < lb[b]) break; |
michael@0 | 330 | } |
michael@0 | 331 | h->count[b] ++; |
michael@0 | 332 | UNLOCK (lock); |
michael@0 | 333 | |
michael@0 | 334 | return 0; |
michael@0 | 335 | } |
michael@0 | 336 | |
michael@0 | 337 | #if defined(_MSC_VER) && defined(_M_IX86) |
michael@0 | 338 | uint64_t readTimestampCounter() |
michael@0 | 339 | { |
michael@0 | 340 | // read the cpu cycle counter. 1 tick = 1 cycle on IA32 |
michael@0 | 341 | _asm rdtsc; |
michael@0 | 342 | } |
michael@0 | 343 | #elif defined(__GNUC__) && (__i386__ || __x86_64__) |
michael@0 | 344 | uint64_t readTimestampCounter() |
michael@0 | 345 | { |
michael@0 | 346 | uint32_t lo, hi; |
michael@0 | 347 | __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); |
michael@0 | 348 | return (uint64_t(hi) << 32) | lo; |
michael@0 | 349 | } |
michael@0 | 350 | #else |
michael@0 | 351 | // add stub for platforms without it, so fat builds don't fail |
michael@0 | 352 | uint64_t readTimestampCounter() { return 0; } |
michael@0 | 353 | #endif |
michael@0 | 354 |