mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-01 05:43:46 +00:00
Bug 555345 - Add profiling capability for JIT-generated code (vprof changes only) (r=rreitmai+)
An earlier patch to tamarin-redux included vprof patches as well as a coordinated set of changes to other files in TR. The vprof directory is imported from nanojit-central, and the vprof changes were overwritten. This patch separates the initialization of new profile records from the logging of data therein, which facilitates the use of the profiling infrastructure from JIT-generated code. --HG-- extra : convert_revision : 10b865fa5d413277c2e11c211302f75d87029f06
This commit is contained in:
parent
3b080ba357
commit
a4204a3095
@ -143,6 +143,7 @@ static void dumpProfile (void)
|
||||
entries = reverse(entries);
|
||||
vprof_printf ("event avg [min : max] total count\n");
|
||||
for (e = entries; e; e = e->next) {
|
||||
if (e->count == 0) continue; // ignore entries with zero count.
|
||||
vprof_printf ("%s", e->file);
|
||||
if (e->line >= 0) {
|
||||
vprof_printf (":%d", e->line);
|
||||
@ -179,23 +180,6 @@ static void dumpProfile (void)
|
||||
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) {
|
||||
@ -206,7 +190,11 @@ inline static entry_t findEntry (char* file, int line)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int profileValue(void** id, char* file, int line, int64_t value, ...)
|
||||
// Initialize the location pointed to by 'id' to a new value profile entry
|
||||
// associated with 'file' and 'line', or do nothing if already initialized.
|
||||
// An optional final argument provides a user-defined probe function.
|
||||
|
||||
int initValueProfile(void** id, char* file, int line, ...)
|
||||
{
|
||||
DO_LOCK (&glock);
|
||||
entry_t e = (entry_t) *id;
|
||||
@ -220,7 +208,7 @@ int profileValue(void** id, char* file, int line, int64_t value, ...)
|
||||
if (e) {
|
||||
*id = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e == NULL) {
|
||||
va_list va;
|
||||
@ -228,72 +216,58 @@ int profileValue(void** id, char* file, int line, int64_t value, ...)
|
||||
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->value = 0;
|
||||
e->sum = 0;
|
||||
e->count = 0;
|
||||
e->min = 0;
|
||||
e->max = 0;
|
||||
// optional probe function argument
|
||||
va_start (va, line);
|
||||
e->func = (void (__cdecl*)(void*)) va_arg (va, void*);
|
||||
va_end (va);
|
||||
|
||||
e->h = NULL;
|
||||
|
||||
e->genptr = NULL;
|
||||
|
||||
VMPI_memset (&e->ivar, 0, sizeof(e->ivar));
|
||||
VMPI_memset (&e->i64var, 0, sizeof(e->i64var));
|
||||
VMPI_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)
|
||||
// Record a value profile event.
|
||||
|
||||
int profileValue(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] ++;
|
||||
e->value = value;
|
||||
if (e->count == 0) {
|
||||
e->sum = value;
|
||||
e->count = 1;
|
||||
e->min = value;
|
||||
e->max = value;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
int histValue(void** id, char* file, int line, int64_t value, int nbins, ...)
|
||||
// Initialize the location pointed to by 'id' to a new histogram profile entry
|
||||
// associated with 'file' and 'line', or do nothing if already initialized.
|
||||
|
||||
int initHistProfile(void** id, char* file, int line, int nbins, ...)
|
||||
{
|
||||
DO_LOCK (&glock);
|
||||
entry_t e = (entry_t) *id;
|
||||
@ -319,11 +293,11 @@ int histValue(void** id, char* file, int line, int64_t value, int nbins, ...)
|
||||
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->value = 0;
|
||||
e->sum = 0;
|
||||
e->count = 0;
|
||||
e->min = 0;
|
||||
e->max = 0;
|
||||
e->func = NULL;
|
||||
e->h = h = (hist_t) malloc (sizeof(hist));
|
||||
n = 1+MAX(nbins,0);
|
||||
@ -343,51 +317,60 @@ int histValue(void** id, char* file, int line, int64_t value, int nbins, ...)
|
||||
lb[b] = MAXINT64;
|
||||
va_end (va);
|
||||
|
||||
for (b = 0; b < nbins; b ++) {
|
||||
if (value < lb[b]) break;
|
||||
}
|
||||
h->count[b] ++;
|
||||
|
||||
e->genptr = NULL;
|
||||
|
||||
VMPI_memset (&e->ivar, 0, sizeof(e->ivar));
|
||||
VMPI_memset (&e->i64var, 0, sizeof(e->i64var));
|
||||
VMPI_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;
|
||||
}
|
||||
|
||||
// Record a histogram profile event.
|
||||
|
||||
int histValue(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;
|
||||
|
||||
LOCK (lock);
|
||||
e->value = value;
|
||||
if (e->count == 0) {
|
||||
e->sum = value;
|
||||
e->count = 1;
|
||||
e->min = value;
|
||||
e->max = value;
|
||||
} else {
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||
inline uint64_t _rdtsc()
|
||||
uint64_t readTimestampCounter()
|
||||
{
|
||||
// read the cpu cycle counter. 1 tick = 1 cycle on IA32
|
||||
_asm rdtsc;
|
||||
}
|
||||
#elif defined(__GNUC__) && (__i386__ || __x86_64__)
|
||||
inline uint64_t _rdtsc()
|
||||
uint64_t readTimestampCounter()
|
||||
{
|
||||
uint32_t lo, hi;
|
||||
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
||||
@ -395,16 +378,6 @@ inline uint64_t _rdtsc()
|
||||
}
|
||||
#else
|
||||
// add stub for platforms without it, so fat builds don't fail
|
||||
inline uint64_t _rdtsc() { return 0; }
|
||||
uint64_t readTimestampCounter() { return 0; }
|
||||
#endif
|
||||
|
||||
void* _tprof_before_id=0;
|
||||
static uint64_t _tprof_before = 0;
|
||||
int64_t _tprof_time()
|
||||
{
|
||||
uint64_t now = _rdtsc();
|
||||
uint64_t v = _tprof_before ? now-_tprof_before : 0;
|
||||
_tprof_before = now;
|
||||
return v/2600; // v = microseconds on a 2.6ghz cpu
|
||||
}
|
||||
|
||||
|
@ -105,12 +105,11 @@
|
||||
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);
|
||||
int64_t _tprof_time();
|
||||
extern void* _tprof_before_id;
|
||||
int initValueProfile(void** id, char* file, int line, ...);
|
||||
int profileValue(void* id, int64_t value);
|
||||
int initHistProfile(void** id, char* file, int line, int nbins, ...);
|
||||
int histValue(void* id, int64_t value);
|
||||
uint64_t readTimestampCounter();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@ -124,73 +123,97 @@ extern void* _tprof_before_id;
|
||||
#define _vprof(v,...)
|
||||
#define _hprof(h,n,...)
|
||||
#define _nhprof(e,v,n,...)
|
||||
#define _ntprof(e)
|
||||
#define _tprof_end()
|
||||
#define _ntprof_begin(e)
|
||||
#define _ntprof_end(e)
|
||||
#define _jvprof_init(id,...)
|
||||
#define _jnvprof_init(id,e,...)
|
||||
#define _jvprof(id,v)
|
||||
#endif // ! VMCFG_SYMBIAN
|
||||
#else
|
||||
|
||||
// Historical/compatibility note:
|
||||
// The macros below were originally written using conditional expressions, not if/else. The original author
|
||||
// said that this was done to allow _vprof and _nvprof to be used in an expression context, but the old code
|
||||
// had already wrapped the macro bodies in { }, so it is not clear how this could have worked. At present,
|
||||
// the profiling macros must appear in a statement context only.
|
||||
|
||||
#define _vprof(v,...) \
|
||||
{ \
|
||||
do { \
|
||||
static void* id = 0; \
|
||||
(id != 0) ? \
|
||||
_profileEntryValue (id, (int64_t) (v)) \
|
||||
: \
|
||||
profileValue (&id, __FILE__, __LINE__, (int64_t) (v), ##__VA_ARGS__, NULL) \
|
||||
;\
|
||||
}
|
||||
if (id == 0) \
|
||||
initValueProfile(&id, __FILE__, __LINE__, ##__VA_ARGS__, NULL); \
|
||||
profileValue(id, (int64_t) (v)); \
|
||||
} while (0)
|
||||
|
||||
#define _nvprof(e,v) \
|
||||
{ \
|
||||
do { \
|
||||
static void* id = 0; \
|
||||
(id != 0) ? \
|
||||
_profileEntryValue (id, (int64_t) (v)) \
|
||||
: \
|
||||
profileValue (&id, (char*) (e), -1, (int64_t) (v), NULL) \
|
||||
; \
|
||||
}
|
||||
if (id == 0) \
|
||||
initValueProfile(&id, (char*) (e), -1, NULL); \
|
||||
profileValue(id, (int64_t) (v)); \
|
||||
} while (0)
|
||||
|
||||
#define _hprof(v,n,...) \
|
||||
{ \
|
||||
do { \
|
||||
static void* id = 0; \
|
||||
(id != 0) ? \
|
||||
_histEntryValue (id, (int64_t) (v)) \
|
||||
: \
|
||||
histValue (&id, __FILE__, __LINE__, (int64_t) (v), (int) (n), ##__VA_ARGS__) \
|
||||
; \
|
||||
}
|
||||
if (id == 0) \
|
||||
initHistProfile(&id, __FILE__, __LINE__, (int) (n), ##__VA_ARGS__); \
|
||||
histValue(id, (int64_t) (v)); \
|
||||
} while (0)
|
||||
|
||||
#define _nhprof(e,v,n,...) \
|
||||
{ \
|
||||
do { \
|
||||
static void* id = 0; \
|
||||
(id != 0) ? \
|
||||
_histEntryValue (id, (int64_t) (v)) \
|
||||
: \
|
||||
histValue (&id, (char*) (e), -1, (int64_t) (v), (int) (n), ##__VA_ARGS__) \
|
||||
; \
|
||||
}
|
||||
if (id == 0) \
|
||||
initHistProfile(&id, (char*) (e), -1, (int) (n), ##__VA_ARGS__); \
|
||||
histValue(id, (int64_t) (v)); \
|
||||
} while (0)
|
||||
|
||||
#define _ntprof(e) \
|
||||
{ \
|
||||
uint64_t v = _tprof_time();\
|
||||
(_tprof_before_id != 0) ? \
|
||||
_profileEntryValue(_tprof_before_id, v)\
|
||||
: 0;\
|
||||
// Profile execution time between _ntprof_begin(e) and _ntprof_end(e).
|
||||
// The tag 'e' must match at the beginning and end of the region to
|
||||
// be timed. Regions may be nested or overlap arbitrarily, as it is
|
||||
// the tag alone that defines the begin/end correspondence.
|
||||
|
||||
#define _ntprof_begin(e) \
|
||||
do { \
|
||||
static void* id = 0; \
|
||||
(id != 0) ? \
|
||||
_profileEntryValue (id, (int64_t) 0) \
|
||||
: \
|
||||
profileValue (&id, (char*)(e), -1, (int64_t) 0, NULL) \
|
||||
;\
|
||||
_tprof_before_id = id;\
|
||||
}
|
||||
if (id == 0) \
|
||||
initValueProfile(&id, (char*)(e), -1, NULL); \
|
||||
((entry_t)id)->i64var[0] = readTimestampCounter(); \
|
||||
} while (0)
|
||||
|
||||
#define _tprof_end() \
|
||||
{\
|
||||
uint64_t v = _tprof_time();\
|
||||
if (_tprof_before_id)\
|
||||
_profileEntryValue(_tprof_before_id, v);\
|
||||
_tprof_before_id = 0;\
|
||||
}
|
||||
// Assume 2.6 Ghz CPU
|
||||
#define TICKS_PER_USEC 2600
|
||||
|
||||
#define _ntprof_end(e) \
|
||||
do { \
|
||||
static void* id = 0; \
|
||||
uint64_t stop = readTimestampCounter(); \
|
||||
if (id == 0) \
|
||||
initValueProfile(&id, (char*)(e), -1, NULL); \
|
||||
uint64_t start = ((entry_t)id)->i64var[0]; \
|
||||
uint64_t usecs = (stop - start) / TICKS_PER_USEC; \
|
||||
profileValue(id, usecs); \
|
||||
} while (0)
|
||||
|
||||
// These macros separate the creation of a profile record from its later usage.
|
||||
// They are intended for profiling JIT-generated code. Once created, the JIT can
|
||||
// bind a pointer to the profile record into the generated code, which can then
|
||||
// record profile events during execution.
|
||||
|
||||
#define _jvprof_init(id,...) \
|
||||
if (*(id) == 0) \
|
||||
initValueProfile((id), __FILE__, __LINE__, ##__VA_ARGS__, NULL)
|
||||
|
||||
#define _jnvprof_init(id,e,...) \
|
||||
if (*(id) == 0) \
|
||||
initValueProfile((id), (char*) (e), -1, ##__VA_ARGS__, NULL)
|
||||
|
||||
// Calls to the _jvprof macro must be wrapped in an actual function
|
||||
// in order to be invoked from JIT-compiled code.
|
||||
|
||||
#define _jvprof(id,v) \
|
||||
profileValue((id), (int64_t) (v))
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user