Add vprof source files (this time for real.)

This commit is contained in:
Andreas Gal 2008-07-31 13:42:25 -07:00
parent e606bdb17e
commit 78535943cb
3 changed files with 698 additions and 0 deletions

93
js/src/vprof/readme.txt Normal file
View File

@ -0,0 +1,93 @@
The two files vprof.h and vprof.cpp implement a simple value-profiling mechanism. By including these two files in avmplus (or any other project), you can value profile data as you wish (currently integers).
Usage:
#include "vprof.h" // in the source file you want to use it
_vprof (value);
At the end of the execution, for each probe you'll get the data associated with the probe, such as:
File line avg [min : max] total count
..\..\pcre\pcre_valid_utf8.cpp 182 50222.75916 [0 : 104947] 4036955604 80381
The probe is defined at line 182 of file pcre_vali_utf8.cpp. It was called 80381 times. The min value of the probe was 0 while its max was 10497 and its average was 50222.75916. The total sum of all values of the probe is 4036955604. Later, I plan to add more options on the spectrum of data among others.
A few typical uses
------------------
To see how many times a given function gets executed do:
void f()
{
_vprof(1);
...
}
void f()
{
_vprof(1);
...
if (...) {
_vprof(1);
...
} else {
_vprof(1);
...
}
}
Here are a few examples of using the value-profiling utility:
_vprof (e);
at the end of program execution, you'll get a dump of the source location of this probe,
its min, max, average, the total sum of all instances of e, and the total number of times this probe was called.
_vprof (x > 0);
shows how many times and what percentage of the cases x was > 0,
that is the probablitiy that x > 0.
_vprof (n % 2 == 0);
shows how many times n was an even number
as well as th probablitiy of n being an even number.
_hprof (n, 4, 1000, 5000, 5001, 10000);
gives you the histogram of n over the given 4 bucket boundaries:
# cases < 1000
# cases >= 1000 and < 5000
# cases >= 5000 and < 5001
# cases >= 5001 and < 10000
# cases >= 10000
_nvprof ("event name", value);
all instances with the same name are merged
so, you can call _vprof with the same event name at difference places
_vprof (e, myProbe);
value profile e and call myProbe (void* vprofID) at the profiling point.
inside the probe, the client has the predefined variables:
_VAL, _COUNT, _SUM, _MIN, _MAX, and the general purpose registers
_IVAR1, ..., IVAR4 general integer registrs
_I64VAR1, ..., I64VAR4 general integer64 registrs
_DVAR1, ..., _DVAR4 general double registers
_GENPTR a generic pointer that can be used by the client
the number of registers can be changed in vprof.h
Named Events
------------
_nvprof ("event name", value);
all instances with the same name are merged
so, you can call _vprof with the same event name at difference places
Custom Probes
--------------
You can call your own custom probe at the profiling point.
_vprof (v, myProbe);
value profile v and call myProbe (void* vprofID) at the profiling point
inside the probe, the client has the predefined variables:
_VAL, _COUNT, _SUM, _MIN, _MAX, and the general purpose registers
_IVAR1, ..., IVAR4 general integer registrs
_I64VAR1, ..., I64VAR4 general integer64 registrs
_DVAR1, ..., _DVAR4 general double registers
the number of registers can be changed in vprof.h
_GENPTR a generic pointer that can be used for almost anything

360
js/src/vprof/vprof.cpp Normal file
View File

@ -0,0 +1,360 @@
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Value-Profiling Utility.
*
* The Initial Developer of the Original Code is
* Intel Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mohammad R. Haghighat [mohammad.r.haghighat@intel.com]
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifdef WIN32
#include "windows.h"
#else
#define __cdecl
#include <stdarg.h>
#include <string.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include "vprof.h"
#define MIN(x,y) ((x) <= (y) ? x : y)
#define MAX(x,y) ((x) >= (y) ? x : y)
#ifndef MAXINT
#define MAXINT int(unsigned(-1)>>1)
#endif
#ifndef MAXINT64
#define MAXINT64 int64_t(uint64_t(-1)>>1)
#endif
#ifndef __STDC_WANT_SECURE_LIB__
#define sprintf_s(b,size,fmt,...) sprintf((b),(fmt),__VA_ARGS__)
#endif
#if THREADED
#define DO_LOCK(lock) Lock(lock); {
#define DO_UNLOCK(lock) }; Unlock(lock)
#else
#define DO_LOCK(lock) { (void)(lock);
#define DO_UNLOCK(lock) }
#endif
#if THREAD_SAFE
#define LOCK(lock) DO_LOCK(lock)
#define UNLOCK(lock) DO_UNLOCK(lock)
#else
#define LOCK(lock) { (void)(lock);
#define UNLOCK(lock) }
#endif
static entry* entries = NULL;
static bool notInitialized = true;
static long glock = LOCK_IS_FREE;
#define Lock(lock) while (_InterlockedCompareExchange(lock, LOCK_IS_TAKEN, LOCK_IS_FREE) == LOCK_IS_TAKEN){};
#define Unlock(lock) _InterlockedCompareExchange(lock, LOCK_IS_FREE, LOCK_IS_TAKEN);
inline static entry* reverse (entry* s)
{
entry_t e, n, p;
p = NULL;
for (e = s; e; e = n) {
n = e->next;
e->next = p;
p = e;
}
return p;
}
static char* f (double d)
{
static char s[80];
char* p;
sprintf_s (s, sizeof(s), "%lf", d);
p = s+strlen(s)-1;
while (*p == '0') {
*p = '\0';
p--;
if (p == s) break;
}
if (*p == '.') *p = '\0';
return s;
}
static void dumpProfile (void)
{
entry_t e;
entries = reverse(entries);
printf ("event avg [min : max] total count\n");
for (e = entries; e; e = e->next) {
printf ("%s", e->file);
if (e->line >= 0) {
printf (":%d", e->line);
}
printf (" %s [%lld : %lld] %lld %lld ",
f(((double)e->sum)/((double)e->count)), e->min, e->max, e->sum, e->count);
if (e->h) {
int j = MAXINT;
for (j = 0; j < e->h->nbins; j ++) {
printf ("(%lld < %lld) ", e->h->count[j], e->h->lb[j]);
}
printf ("(%lld >= %lld) ", e->h->count[e->h->nbins], e->h->lb[e->h->nbins-1]);
}
if (e->func) {
int j;
for (j = 0; j < NUM_EVARS; j++) {
if (e->ivar[j] != 0) {
printf ("IVAR%d %d ", j, e->ivar[j]);
}
}
for (j = 0; j < NUM_EVARS; j++) {
if (e->i64var[j] != 0) {
printf ("I64VAR%d %lld ", j, e->i64var[j]);
}
}
for (j = 0; j < NUM_EVARS; j++) {
if (e->dvar[j] != 0) {
printf ("DVAR%d %lf ", j, e->dvar[j]);
}
}
}
printf ("\n");
}
entries = reverse(entries);
}
int _profileEntryValue (void* id, int64_t value)
{
entry_t e = (entry_t) id;
long* lock = &(e->lock);
LOCK (lock);
e->value = value;
e->sum += value;
e->count ++;
e->min = MIN (e->min, value);
e->max = MAX (e->max, value);
if (e->func) e->func (e);
UNLOCK (lock);
return 0;
}
inline static entry_t findEntry (char* file, int line)
{
for (entry_t e = entries; e; e = e->next) {
if ((e->line == line) && (strcmp (e->file, file) == 0)) {
return e;
}
}
return NULL;
}
int profileValue(void** id, char* file, int line, int64_t value, ...)
{
DO_LOCK (&glock);
entry_t e = (entry_t) *id;
if (notInitialized) {
atexit (dumpProfile);
notInitialized = false;
}
if (e == NULL) {
e = findEntry (file, line);
if (e) {
*id = e;
}
}
if (e == NULL) {
va_list va;
e = (entry_t) malloc (sizeof(entry));
e->lock = LOCK_IS_FREE;
e->file = file;
e->line = line;
e->value = value;
e->sum = value;
e->count = 1;
e->min = value;
e->max = value;
va_start (va, value);
e->func = (void (__cdecl*)(void*)) va_arg (va, void*);
va_end (va);
e->h = NULL;
e->genptr = NULL;
memset (&e->ivar, 0, sizeof(e->ivar));
memset (&e->i64var, 0, sizeof(e->i64var));
memset (&e->dvar, 0, sizeof(e->dvar));
e->next = entries;
entries = e;
if (e->func) e->func (e);
*id = e;
} else {
long* lock = &(e->lock);
LOCK (lock);
e->value = value;
e->sum += value;
e->count ++;
e->min = MIN (e->min, value);
e->max = MAX (e->max, value);
if (e->func) e->func (e);
UNLOCK (lock);
}
DO_UNLOCK (&glock);
return 0;
}
int _histEntryValue (void* id, int64_t value)
{
entry_t e = (entry_t) id;
long* lock = &(e->lock);
hist_t h = e->h;
int nbins = h->nbins;
int64_t* lb = h->lb;
int b;
for (b = 0; b < nbins; b ++) {
if (value < lb[b]) break;
}
LOCK (lock);
e->value = value;
e->sum += value;
e->count ++;
e->min = MIN (e->min, value);
e->max = MAX (e->max, value);
h->count[b] ++;
UNLOCK (lock);
return 0;
}
int histValue(void** id, char* file, int line, int64_t value, int nbins, ...)
{
DO_LOCK (&glock);
entry_t e = (entry_t) *id;
if (notInitialized) {
atexit (dumpProfile);
notInitialized = false;
}
if (e == NULL) {
e = findEntry (file, line);
if (e) {
*id = e;
}
}
if (e == NULL) {
va_list va;
hist_t h;
int b, n, s;
int64_t* lb;
e = (entry_t) malloc (sizeof(entry));
e->lock = LOCK_IS_FREE;
e->file = file;
e->line = line;
e->value = value;
e->sum = value;
e->count = 1;
e->min = value;
e->max = value;
e->func = NULL;
e->h = h = (hist_t) malloc (sizeof(hist));
n = 1+MAX(nbins,0);
h->nbins = n-1;
s = n*sizeof(int64_t);
lb = (int64_t*) malloc (s);
h->lb = lb;
memset (h->lb, 0, s);
h->count = (int64_t*) malloc (s);
memset (h->count, 0, s);
va_start (va, nbins);
for (b = 0; b < nbins; b++) {
//lb[b] = va_arg (va, int64_t);
lb[b] = va_arg (va, int);
}
lb[b] = MAXINT64;
va_end (va);
for (b = 0; b < nbins; b ++) {
if (value < lb[b]) break;
}
h->count[b] ++;
e->genptr = NULL;
memset (&e->ivar, 0, sizeof(e->ivar));
memset (&e->i64var, 0, sizeof(e->i64var));
memset (&e->dvar, 0, sizeof(e->dvar));
e->next = entries;
entries = e;
*id = e;
} else {
int b;
long* lock = &(e->lock);
hist_t h=e->h;
int64_t* lb = h->lb;
LOCK (lock);
e->value = value;
e->sum += value;
e->count ++;
e->min = MIN (e->min, value);
e->max = MAX (e->max, value);
for (b = 0; b < nbins; b ++) {
if (value < lb[b]) break;
}
h->count[b] ++;
UNLOCK (lock);
}
DO_UNLOCK (&glock);
return 0;
}

245
js/src/vprof/vprof.h Normal file
View File

@ -0,0 +1,245 @@
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Value-Profiling Utility.
*
* The Initial Developer of the Original Code is
* Intel Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mohammad R. Haghighat [mohammad.r.haghighat@intel.com]
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
//
// Here are a few examples of using the value-profiling utility:
//
// _vprof (e);
// at the end of program execution, you'll get a dump of the source location of this probe,
// its min, max, average, the total sum of all instances of e, and the total number of times this probe was called.
//
// _vprof (x > 0);
// shows how many times and what percentage of the cases x was > 0,
// that is the probablitiy that x > 0.
//
// _vprof (n % 2 == 0);
// shows how many times n was an even number
// as well as th probablitiy of n being an even number.
//
// _hprof (n, 4, 1000, 5000, 5001, 10000);
// gives you the histogram of n over the given 4 bucket boundaries:
// # cases < 1000
// # cases >= 1000 and < 5000
// # cases >= 5000 and < 5001
// # cases >= 5001 and < 10000
// # cases >= 10000
//
// _nvprof ("event name", value);
// all instances with the same name are merged
// so, you can call _vprof with the same event name at difference places
//
// _vprof (e, myProbe);
// value profile e and call myProbe (void* vprofID) at the profiling point.
// inside the probe, the client has the predefined variables:
// _VAL, _COUNT, _SUM, _MIN, _MAX, and the general purpose registers
// _IVAR1, ..., IVAR4 general integer registrs
// _I64VAR1, ..., I64VAR4 general integer64 registrs
// _DVAR1, ..., _DVAR4 general double registers
// _GENPTR a generic pointer that can be used by the client
// the number of registers can be changed in vprof.h
//
#ifndef __VPROF__
#define __VPROF__
//
// If the application for which you want to use vprof is threaded, THREADED must be defined as 1, otherwise define it as 0
//
// If your application is not threaded, define THREAD_SAFE 0,
// otherwise, you have the option of setting THREAD_SAFE to 1 which results in exact counts or to 0 which results in a much more efficient but non-exact counts
//
#define THREADED 0
#define THREAD_SAFE 0
#ifdef _MSC_VER
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef signed char int8_t;
typedef short int16_t;
typedef unsigned int uint32_t;
typedef signed int int32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
#else
#include <inttypes.h>
#endif
// portable align macro
#if defined(_MSC_VER)
#define vprof_align8(t) __declspec(align(8)) t
#elif defined(__GNUC__)
#define vprof_align8(t) t __attribute__ ((aligned (8)))
#endif
#ifdef __cplusplus
extern "C" {
#endif
int profileValue (void** id, char* file, int line, int64_t value, ...);
int _profileEntryValue (void* id, int64_t value);
int histValue(void** id, char* file, int line, int64_t value, int nbins, ...);
int _histEntryValue (void* id, int64_t value);
#ifdef __cplusplus
}
#endif
#define DOPROF
#ifndef DOPROF
#define _vprof(v)
#define _hprof(h)
#else
#define _vprof(v,...) \
{ \
static void* id = 0; \
(id != 0) ? \
_profileEntryValue (id, (int64_t) (v)) \
: \
profileValue (&id, __FILE__, __LINE__, (int64_t) (v), ##__VA_ARGS__, NULL) \
;\
}
#define _nvprof(e,v,...) \
{ \
static void* id = 0; \
(id != 0) ? \
_profileEntryValue (id, (int64_t) (v)) \
: \
profileValue (&id, (char*) (e), -1, (int64_t) (v), ##__VA_ARGS__, NULL) \
; \
}
#define _hprof(v,n,...) \
{ \
static void* id = 0; \
(id != 0) ? \
_histEntryValue (id, (int64_t) (v)) \
: \
histValue (&id, __FILE__, __LINE__, (int64_t) (v), (int) (n), ##__VA_ARGS__) \
; \
}
#define _nhprof(e,v,n,...) \
{ \
static void* id = 0; \
(id != 0) ? \
_histEntryValue (id, (int64_t) (v)) \
: \
histValue (&id, (char*) (e), -1, (int64_t) (v), (int) (n), ##__VA_ARGS__) \
; \
}
#endif
#define NUM_EVARS 4
typedef enum {
LOCK_IS_FREE = 0,
LOCK_IS_TAKEN = 1
};
extern
#ifdef __cplusplus
"C"
#endif
long _InterlockedCompareExchange (
long volatile * Destination,
long Exchange,
long Comperand
);
typedef struct hist hist;
typedef struct hist {
int nbins;
int64_t* lb;
int64_t* count;
} *hist_t;
typedef struct entry entry;
typedef struct entry {
long lock;
char* file;
int line;
int64_t value;
int64_t count;
int64_t sum;
int64_t min;
int64_t max;
void (*func)(void*);
hist* h;
entry* next;
// exposed to the clients
void* genptr;
int ivar[NUM_EVARS];
vprof_align8(int64_t) i64var[NUM_EVARS];
vprof_align8(double) dvar[NUM_EVARS];
//
char pad[128]; // avoid false sharing
} *entry_t;
#define _VAL ((entry_t)vprofID)->value
#define _COUNT ((entry_t)vprofID)->count
#define _SUM ((entry_t)vprofID)->sum
#define _MIN ((entry_t)vprofID)->min
#define _MAX ((entry_t)vprofID)->max
#define _GENPTR ((entry_t)vprofID)->genptr
#define _IVAR0 ((entry_t)vprofID)->ivar[0]
#define _IVAR1 ((entry_t)vprofID)->ivar[1]
#define _IVAR2 ((entry_t)vprofID)->ivar[2]
#define _IVAR3 ((entry_t)vprofID)->ivar[3]
#define _I64VAR0 ((entry_t)vprofID)->i64var[0]
#define _I64VAR1 ((entry_t)vprofID)->i64var[1]
#define _I64VAR2 ((entry_t)vprofID)->i64var[2]
#define _I64VAR3 ((entry_t)vprofID)->i64var[3]
#define _DVAR0 ((entry_t)vprofID)->dvar[0]
#define _DVAR1 ((entry_t)vprofID)->dvar[1]
#define _DVAR2 ((entry_t)vprofID)->dvar[2]
#define _DVAR3 ((entry_t)vprofID)->dvar[3]
#endif /* __VPROF__ */