gcc/libgo/runtime/cpuprof.c

351 lines
10 KiB
C
Raw Normal View History

// AUTO-GENERATED by autogen.sh; DO NOT EDIT
#include "runtime.h"
#include "arch.h"
#include "malloc.h"
#include "array.h"
#line 57 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
typedef struct __go_open_array Slice;
#define array __values
#define len __count
#define cap __capacity
#line 62 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
enum
{
HashSize = 1<<10 ,
LogSize = 1<<17 ,
Assoc = 4 ,
MaxStack = 64 ,
} ;
#line 70 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
typedef struct Profile Profile;
typedef struct Bucket Bucket;
typedef struct Entry Entry;
#line 74 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
struct Entry {
uintptr count;
uintptr depth;
uintptr stack[MaxStack];
} ;
#line 80 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
struct Bucket {
Entry entry[Assoc];
} ;
#line 84 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
struct Profile {
bool on;
Note wait;
uintptr count;
uintptr evicts;
uintptr lost;
uintptr totallost;
#line 93 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
Bucket hash[HashSize];
#line 98 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
uintptr log[2][LogSize/2];
uintptr nlog;
int32 toggle;
uint32 handoff;
#line 106 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
uint32 wtoggle;
bool wholding;
bool flushing;
bool eod_sent;
} ;
#line 112 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
static Lock lk;
static Profile *prof;
#line 115 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
static void tick ( uintptr* , int32 ) ;
static void add ( Profile* , uintptr* , int32 ) ;
static bool evict ( Profile* , Entry* ) ;
static bool flushlog ( Profile* ) ;
#line 120 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
static uintptr eod[3] = { 0 , 1 , 0 } ;
#line 125 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
static void
LostProfileData ( void )
{
}
#line 130 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
extern void runtime_SetCPUProfileRate ( intgo )
__asm__ ( GOSYM_PREFIX "runtime.SetCPUProfileRate" ) ;
#line 135 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
void
runtime_SetCPUProfileRate ( intgo hz )
{
uintptr *p;
uintptr n;
#line 142 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
if ( hz < 0 )
hz = 0;
if ( hz > 1000000 )
hz = 1000000;
#line 147 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
runtime_lock ( &lk ) ;
if ( hz > 0 ) {
if ( prof == nil ) {
prof = runtime_SysAlloc ( sizeof *prof , &mstats.other_sys ) ;
if ( prof == nil ) {
runtime_printf ( "runtime: cpu profiling cannot allocate memory\n" ) ;
runtime_unlock ( &lk ) ;
return;
}
}
if ( prof->on || prof->handoff != 0 ) {
runtime_printf ( "runtime: cannot set cpu profile rate until previous profile has finished.\n" ) ;
runtime_unlock ( &lk ) ;
return;
}
#line 163 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
prof->on = true;
p = prof->log[0];
#line 167 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
*p++ = 0;
*p++ = 3;
*p++ = 0;
*p++ = 1000000 / hz;
*p++ = 0;
prof->nlog = p - prof->log[0];
prof->toggle = 0;
prof->wholding = false;
prof->wtoggle = 0;
prof->flushing = false;
prof->eod_sent = false;
runtime_noteclear ( &prof->wait ) ;
#line 180 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
runtime_setcpuprofilerate ( tick , hz ) ;
} else if ( prof != nil && prof->on ) {
runtime_setcpuprofilerate ( nil , 0 ) ;
prof->on = false;
#line 187 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
for ( ;; ) {
n = prof->handoff;
if ( n&0x80000000 )
runtime_printf ( "runtime: setcpuprofile(off) twice" ) ;
if ( runtime_cas ( &prof->handoff , n , n|0x80000000 ) )
break;
}
if ( n == 0 ) {
#line 196 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
runtime_notewakeup ( &prof->wait ) ;
}
}
runtime_unlock ( &lk ) ;
}
#line 202 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
static void
tick ( uintptr *pc , int32 n )
{
add ( prof , pc , n ) ;
}
#line 213 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
static void
add ( Profile *p , uintptr *pc , int32 n )
{
int32 i , j;
uintptr h , x;
Bucket *b;
Entry *e;
#line 221 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
if ( n > MaxStack )
n = MaxStack;
#line 225 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
h = 0;
for ( i=0; i<n; i++ ) {
h = h<<8 | ( h>> ( 8* ( sizeof ( h ) -1 ) ) ) ;
x = pc[i];
h += x*31 + x*7 + x*3;
}
p->count++;
#line 234 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
b = &p->hash[h%HashSize];
for ( i=0; i<Assoc; i++ ) {
e = &b->entry[i];
if ( e->depth != ( uintptr ) n )
continue;
for ( j=0; j<n; j++ )
if ( e->stack[j] != pc[j] )
goto ContinueAssoc;
e->count++;
return;
ContinueAssoc:;
}
#line 248 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
e = &b->entry[0];
for ( i=1; i<Assoc; i++ )
if ( b->entry[i].count < e->count )
e = &b->entry[i];
if ( e->count > 0 ) {
if ( !evict ( p , e ) ) {
#line 255 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
p->lost++;
p->totallost++;
return;
}
p->evicts++;
}
#line 263 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
e->depth = n;
e->count = 1;
for ( i=0; i<n; i++ )
e->stack[i] = pc[i];
}
#line 275 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
static bool
evict ( Profile *p , Entry *e )
{
int32 i , d , nslot;
uintptr *log , *q;
#line 281 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
d = e->depth;
nslot = d+2;
log = p->log[p->toggle];
if ( p->nlog+nslot > nelem ( p->log[0] ) ) {
if ( !flushlog ( p ) )
return false;
log = p->log[p->toggle];
}
#line 290 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
q = log+p->nlog;
*q++ = e->count;
*q++ = d;
for ( i=0; i<d; i++ )
*q++ = e->stack[i];
p->nlog = q - log;
e->count = 0;
return true;
}
#line 304 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
static bool
flushlog ( Profile *p )
{
uintptr *log , *q;
#line 309 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
if ( !runtime_cas ( &p->handoff , 0 , p->nlog ) )
return false;
runtime_notewakeup ( &p->wait ) ;
#line 313 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
p->toggle = 1 - p->toggle;
log = p->log[p->toggle];
q = log;
if ( p->lost > 0 ) {
*q++ = p->lost;
*q++ = 1;
*q++ = ( uintptr ) LostProfileData;
}
p->nlog = q - log;
return true;
}
#line 327 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
Slice
getprofile ( Profile *p )
{
uint32 i , j , n;
Slice ret;
Bucket *b;
Entry *e;
#line 335 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
ret.array = nil;
ret.len = 0;
ret.cap = 0;
#line 339 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
if ( p == nil )
return ret;
#line 342 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
if ( p->wholding ) {
#line 345 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
for ( ;; ) {
n = p->handoff;
if ( n == 0 ) {
runtime_printf ( "runtime: phase error during cpu profile handoff\n" ) ;
return ret;
}
if ( n & 0x80000000 ) {
p->wtoggle = 1 - p->wtoggle;
p->wholding = false;
p->flushing = true;
goto flush;
}
if ( runtime_cas ( &p->handoff , n , 0 ) )
break;
}
p->wtoggle = 1 - p->wtoggle;
p->wholding = false;
}
#line 364 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
if ( p->flushing )
goto flush;
#line 367 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
if ( !p->on && p->handoff == 0 )
return ret;
#line 371 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
runtime_notetsleepg ( &p->wait , -1 ) ;
runtime_noteclear ( &p->wait ) ;
#line 374 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
n = p->handoff;
if ( n == 0 ) {
runtime_printf ( "runtime: phase error during cpu profile wait\n" ) ;
return ret;
}
if ( n == 0x80000000 ) {
p->flushing = true;
goto flush;
}
n &= ~0x80000000;
#line 386 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
p->wholding = true;
#line 388 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
ret.array = ( byte* ) p->log[p->wtoggle];
ret.len = n*sizeof ( uintptr ) ;
ret.cap = ret.len;
return ret;
#line 393 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
flush:
#line 398 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
for ( i=0; i<HashSize; i++ ) {
b = &p->hash[i];
for ( j=0; j<Assoc; j++ ) {
e = &b->entry[j];
if ( e->count > 0 && !evict ( p , e ) ) {
#line 404 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
goto breakflush;
}
}
}
breakflush:
#line 411 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
if ( p->nlog > 0 ) {
#line 414 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
ret.array = ( byte* ) p->log[p->toggle];
ret.len = p->nlog*sizeof ( uintptr ) ;
ret.cap = ret.len;
p->nlog = 0;
return ret;
}
#line 422 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
if ( !p->eod_sent ) {
#line 425 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
p->eod_sent = true;
ret.array = ( byte* ) eod;
ret.len = sizeof eod;
ret.cap = ret.len;
return ret;
}
#line 433 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
p->flushing = false;
if ( !runtime_cas ( &p->handoff , p->handoff , 0 ) )
runtime_printf ( "runtime: profile flush racing with something\n" ) ;
return ret;
}
Slice runtime_CPUProfile() __asm__ (GOSYM_PREFIX "runtime.CPUProfile");
Slice runtime_CPUProfile()
{
Slice ret;
#line 441 "../../../trunk/libgo/runtime/../../../trunk/libgo/runtime/cpuprof.goc"
ret = getprofile(prof);
return ret;
}