void stats_gauge_pass( int64_t tval, void *arg ) { struct timespec tv[4]; int64_t nsec; char *prfx; ST_THR *c; time_t ts; DHASH *d; IOBUF *b; int i; c = (ST_THR *) arg; ts = (time_t) tvalts( tval ); prfx = ctl->stats->gauge->prefix; #ifdef DEBUG debug( "[%02d] Gauge claim", c->id ); #endif clock_gettime( CLOCK_REALTIME, &(tv[0]) ); // take the data for( i = 0; i < c->conf->hsize; i++ ) if( ( i % c->max ) == c->id ) for( d = c->conf->data[i]; d; d = d->next ) if( d->in.sum.count ) { lock_gauge( d ); d->proc.sum = d->in.sum; // don't reset the gauge, just the count d->in.sum.count = 0; unlock_gauge( d ); } else if( d->empty >= 0 ) d->empty++; #ifdef CALC_JITTER clock_gettime( CLOCK_REALTIME, &(tv[1]) ); // sleep a bit to avoid contention usleep( 1000 + ( random( ) % 30011 ) ); #endif #ifdef DEBUG debug( "[%02d] Gauge report", c->id ); #endif clock_gettime( CLOCK_REALTIME, &(tv[2]) ); c->active = 0; c->points = 0; b = mem_new_buf( IO_BUF_SZ ); // and report it for( i = 0; i < c->conf->hsize; i++ ) if( ( i % c->max ) == c->id ) for( d = c->conf->data[i]; d; d = d->next ) { // we report gauges anyway, updated or not bprintf( "%s %f", d->path, d->proc.sum.total ); if( d->proc.sum.count ) { if( d->empty > 0 ) d->empty = 0; // keep count c->points += d->proc.sum.count; c->active++; // and zero that d->proc.sum.count = 0; } } clock_gettime( CLOCK_REALTIME, &(tv[3]) ); if( ctl->stats->self->enable ) { // report some self stats prfx = ctl->stats->self->prefix; bprintf( "%s.points %d", c->wkrstr, c->points ); bprintf( "%s.active %d", c->wkrstr, c->active ); nsec = tsll( tv[0] ) - tval; bprintf( "%s.delay %lu", c->wkrstr, nsec / 1000 ); #ifdef CALC_JITTER nsec = tsll( tv[1] ) - tsll( tv[0] ); #else nsec = tsll( tv[2] ) - tsll( tv[0] ); #endif bprintf( "%s.steal %lu", c->wkrstr, nsec / 1000 ); nsec = tsll( tv[3] ) - tsll( tv[2] ); bprintf( "%s.stats %lu", c->wkrstr, nsec / 1000 ); nsec = tsll( tv[3] ) - tval; bprintf( "%s.usec %lu", c->wkrstr, nsec / 1000 ); } io_buf_send( b ); }
void stats_stats_pass( int64_t tval, void *arg ) { struct timespec tv[4]; int64_t nsec; char *prfx; time_t ts; ST_THR *c; DHASH *d; IOBUF *b; int i; c = (ST_THR *) arg; ts = (time_t) tvalts( tval ); #ifdef DEBUG debug( "[%02d] Stats claim", c->id ); #endif clock_gettime( CLOCK_REALTIME, &(tv[0]) ); // take the data for( i = 0; i < c->conf->hsize; i++ ) if( ( i % c->max ) == c->id ) for( d = c->conf->data[i]; d; d = d->next ) if( d->in.points ) { lock_stats( d ); d->proc.points = d->in.points; d->in.points = NULL; unlock_stats( d ); } else if( d->empty >= 0 ) d->empty++; #ifdef CALC_JITTER clock_gettime( CLOCK_REALTIME, &(tv[1]) ); // sleep a bit to avoid contention usleep( 1000 + ( random( ) % 30011 ) ); #endif #ifdef DEBUG debug( "[%02d] Stats report", c->id ); #endif clock_gettime( CLOCK_REALTIME, &(tv[2]) ); c->points = 0; c->active = 0; b = mem_new_buf( IO_BUF_SZ ); // and report it for( i = 0; i < c->conf->hsize; i++ ) if( ( i % c->max ) == c->id ) for( d = c->conf->data[i]; d; d = d->next ) if( d->proc.points ) { if( d->empty > 0 ) d->empty = 0; // the buffer can get changed during // this function c->points += stats_report_one( d, c, ts, &b ); c->active++; } // and work out how long that took clock_gettime( CLOCK_REALTIME, &(tv[3]) ); if( ctl->stats->self->enable ) { // report some self stats prfx = ctl->stats->self->prefix; bprintf( "%s.points %d", c->wkrstr, c->points ); bprintf( "%s.active %d", c->wkrstr, c->active ); bprintf( "%s.workspace %d", c->wkrstr, c->wkspcsz ); nsec = tsll( tv[0] ) - tval; bprintf( "%s.delay %lu", c->wkrstr, nsec / 1000 ); #ifdef CALC_JITTER nsec = tsll( tv[1] ) - tsll( tv[0] ); #else nsec = tsll( tv[2] ) - tsll( tv[0] ); #endif bprintf( "%s.steal %lu", c->wkrstr, nsec / 1000 ); nsec = tsll( tv[3] ) - tsll( tv[2] ); bprintf( "%s.stats %lu", c->wkrstr, nsec / 1000 ); nsec = tsll( tv[3] ) - tval; bprintf( "%s.usec %lu", c->wkrstr, nsec / 1000 ); } io_buf_send( b ); }
void stats_adder_pass( int64_t tval, void *arg ) { struct timespec tv[4]; int64_t nsec; char *prfx; ST_THR *c; time_t ts; DHASH *d; IOBUF *b; int i; c = (ST_THR *) arg; ts = (time_t) tvalts( tval ); prfx = ctl->stats->adder->prefix; #ifdef DEBUG debug( "[%02d] Adder claim", c->id ); #endif clock_gettime( CLOCK_REALTIME, &(tv[0]) ); // take the data for( i = 0; i < c->conf->hsize; i++ ) if( ( i % c->max ) == c->id ) for( d = c->conf->data[i]; d; d = d->next ) if( d->in.sum.count > 0 ) { lock_adder( d ); d->proc.sum = d->in.sum; d->in.sum.total = 0; d->in.sum.count = 0; unlock_adder( d ); } else if( d->empty >= 0 ) d->empty++; clock_gettime( CLOCK_REALTIME, &(tv[1]) ); //debug( "[%02d] Unlocking adder lock.", c->id ); // synth thread is waiting for this unlock_stthr( c ); //debug( "[%02d] Trying to lock synth.", c->id ); // try to lock the synth thread lock_synth( ); //debug( "[%02d] Unlocking synth.", c->id ); // and then unlock it unlock_synth( ); //debug( "[%02d] Trying to get our own lock back.", c->id ); // and lock our own again lock_stthr( c ); //debug( "[%02d] Sleeping a little before processing.", c->id ); #ifdef CALC_JITTER // sleep a short time to avoid contention usleep( 1000 + ( random( ) % 30011 ) ); #endif #ifdef DEBUG debug( "[%02d] Adder report", c->id ); #endif clock_gettime( CLOCK_REALTIME, &(tv[2]) ); // zero the counters c->points = 0; c->active = 0; b = mem_new_buf( IO_BUF_SZ ); // and report it for( i = 0; i < c->conf->hsize; i++ ) if( ( i % c->max ) == c->id ) for( d = c->conf->data[i]; d; d = d->next ) if( d->proc.sum.count > 0 ) { if( d->empty > 0 ) d->empty = 0; bprintf( "%s %f", d->path, d->proc.sum.total ); // keep count c->points += d->proc.sum.count; c->active++; // and zero that d->proc.sum.count = 0; } // and work out how long that took clock_gettime( CLOCK_REALTIME, &(tv[3]) ); if( ctl->stats->self->enable ) { // report some self stats prfx = ctl->stats->self->prefix; bprintf( "%s.points %d", c->wkrstr, c->points ); bprintf( "%s.active %d", c->wkrstr, c->active ); nsec = tsll( tv[0] ) - tval; bprintf( "%s.delay %lu", c->wkrstr, nsec / 1000 ); nsec = tsll( tv[1] ) - tsll( tv[0] ); bprintf( "%s.steal %lu", c->wkrstr, nsec / 1000 ); nsec = tsll( tv[3] ) - tsll( tv[2] ); bprintf( "%s.stats %lu", c->wkrstr, nsec / 1000 ); nsec = tsll( tv[3] ) - tval; bprintf( "%s.usec %lu", c->wkrstr, nsec / 1000 ); } io_buf_send( b ); }
// we do integer maths here to avoid creeping // double-precision addition inaccuracies void loop_control( const char *name, loop_call_fn *fp, void *arg, int usec, int flags, int offset ) { int64_t timer, intv, nsec, offs, diff, t, skips, fires; int i, ticks = 1, curr = 0; struct timespec ts; #ifdef DEBUG_LOOPS int64_t marker = 1; #endif // convert to nsec nsec = 1000 * (int64_t) usec; offs = 1000 * (int64_t) offset; // the actual sleep interval may be less // if period is too high intv = nsec; // wind down to an acceptable interval // try to avoid issues while( ( flags & LOOP_TRIM ) && intv > MAX_LOOP_NSEC && intv > offs ) { for( i = 0; i < 8; i++ ) if( ( intv % loop_control_factors[i] ) == 0 ) break; // if we can't find a suitable factor then try 2 // this may introduce long-term instability :-( if( i == 8 ) { warn( "Could not find a suitable prime factor for %s interval nsec.", name ); i = 0; } // and adjust intv /= loop_control_factors[i]; ticks *= loop_control_factors[i]; } if( ticks > 1 ) debug( "Loop %s trimmed from %ld to %ld nsec interval.", name, nsec, intv ); // get the time clock_gettime( CLOCK_REALTIME, &ts ); timer = tsll( ts ); // do we synchronise to a clock? if( flags & LOOP_SYNC ) { t = timer + offs + nsec - ( timer % nsec ); diff = t - timer; timer = t; llts( diff, ts ); nanosleep( &ts, NULL ); debug( "Pushed paper for %d usec to synchronize %s loop.", diff / 1000, name ); } fires = 0; skips = 0; // say a loop has started loop_mark_start( name ); while( ctl->run_flags & RUN_LOOP ) { // decide if we are firing the payload if( ++curr == ticks ) { #ifdef DEBUG_LOOPS if( !( flags & LOOP_SILENT ) ) debug_loop( "Calling payload %s", name ); #endif (*fp)( timer, arg ); fires++; curr = 0; } // roll on the timer timer += intv; // get the current time clock_gettime( CLOCK_REALTIME, &ts ); t = tsll( ts ); // don't do negative sleep if( t < timer ) { // and sleep diff = timer - t; llts( diff, ts ); nanosleep( &ts, NULL ); } else { skips++; #ifdef DEBUG_LOOPS if( skips == marker ) { debug( "Loop %s skips: %ld", name, skips ); marker = marker << 1; } #endif } } // and say it's finished loop_mark_done( name, skips, fires ); }