Blame src/extras.c

Packit 577717
/****************************/
Packit 577717
/* THIS IS OPEN SOURCE CODE */
Packit 577717
/****************************/
Packit 577717
Packit 577717
/* 
Packit 577717
* File:    extras.c
Packit 577717
* Author:  Philip Mucci
Packit 577717
*          mucci@cs.utk.edu
Packit 577717
* Mods:    dan terpstra
Packit 577717
*          terpstra@cs.utk.edu
Packit 577717
* Mods:    Haihang You
Packit 577717
*          you@cs.utk.edu
Packit 577717
* Mods:    Kevin London
Packit 577717
*          london@cs.utk.edu
Packit 577717
* Mods:    Maynard Johnson
Packit 577717
*          maynardj@us.ibm.com
Packit 577717
*/
Packit 577717
Packit 577717
/* This file contains portable routines to do things that we wish the
Packit 577717
vendors did in the kernel extensions or performance libraries. */
Packit 577717
Packit 577717
#include "papi.h"
Packit 577717
#include "papi_internal.h"
Packit 577717
#include "papi_vector.h"
Packit 577717
#include "papi_memory.h"
Packit 577717
#include "extras.h"
Packit 577717
#include "threads.h"
Packit 577717
Packit 577717
#if (!defined(HAVE_FFSLL) || defined(__bgp__))
Packit 577717
int ffsll( long long lli );
Packit 577717
#else
Packit 577717
#include <string.h>
Packit 577717
#endif
Packit 577717
Packit 577717
/****************/
Packit 577717
/* BEGIN LOCALS */
Packit 577717
/****************/
Packit 577717
Packit 577717
static unsigned int _rnum = DEADBEEF;
Packit 577717
Packit 577717
/**************/
Packit 577717
/* END LOCALS */
Packit 577717
/**************/
Packit 577717
Packit 577717
inline_static unsigned short
Packit 577717
random_ushort( void )
Packit 577717
{
Packit 577717
	return ( unsigned short ) ( _rnum = 1664525 * _rnum + 1013904223 );
Packit 577717
}
Packit 577717
Packit 577717
Packit 577717
/* compute the amount by which to increment the bucket.
Packit 577717
   value is the current value of the bucket
Packit 577717
   this routine is used by all three profiling cases
Packit 577717
   it is inlined for speed
Packit 577717
*/
Packit 577717
inline_static int
Packit 577717
profil_increment( long long value,
Packit 577717
				  int flags, long long excess, long long threshold )
Packit 577717
{
Packit 577717
	int increment = 1;
Packit 577717
Packit 577717
	if ( flags == PAPI_PROFIL_POSIX ) {
Packit 577717
		return ( 1 );
Packit 577717
	}
Packit 577717
Packit 577717
	if ( flags & PAPI_PROFIL_RANDOM ) {
Packit 577717
		if ( random_ushort(  ) <= ( USHRT_MAX / 4 ) )
Packit 577717
			return ( 0 );
Packit 577717
	}
Packit 577717
Packit 577717
	if ( flags & PAPI_PROFIL_COMPRESS ) {
Packit 577717
		/* We're likely to ignore the sample if buf[address] gets big. */
Packit 577717
		if ( random_ushort(  ) < value ) {
Packit 577717
			return ( 0 );
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	if ( flags & PAPI_PROFIL_WEIGHTED ) {	/* Increment is between 1 and 255 */
Packit 577717
		if ( excess <= ( long long ) 1 )
Packit 577717
			increment = 1;
Packit 577717
		else if ( excess > threshold )
Packit 577717
			increment = 255;
Packit 577717
		else {
Packit 577717
			threshold = threshold / ( long long ) 255;
Packit 577717
			increment = ( int ) ( excess / threshold );
Packit 577717
		}
Packit 577717
	}
Packit 577717
	return ( increment );
Packit 577717
}
Packit 577717
Packit 577717
Packit 577717
static void
Packit 577717
posix_profil( caddr_t address, PAPI_sprofil_t * prof,
Packit 577717
			  int flags, long long excess, long long threshold )
Packit 577717
{
Packit 577717
	unsigned short *buf16;
Packit 577717
	unsigned int *buf32;
Packit 577717
	unsigned long long *buf64;
Packit 577717
	unsigned long indx;
Packit 577717
	unsigned long long lloffset;
Packit 577717
Packit 577717
	/* SPECIAL CASE: if starting address is 0 and scale factor is 2
Packit 577717
	   then all counts go into first bin.
Packit 577717
	 */
Packit 577717
	if ( ( prof->pr_off == 0 ) && ( prof->pr_scale == 0x2 ) )
Packit 577717
		indx = 0;
Packit 577717
	else {
Packit 577717
		/* compute the profile buffer offset by:
Packit 577717
		   - subtracting the profiling base address from the pc address
Packit 577717
		   - multiplying by the scaling factor
Packit 577717
		   - dividing by max scale (65536, or 2^^16) 
Packit 577717
		   - dividing by implicit 2 (2^^1 for a total of 2^^17), for even addresses
Packit 577717
		   NOTE: 131072 is a valid scale value. It produces byte resolution of addresses
Packit 577717
		 */
Packit 577717
		lloffset =
Packit 577717
			( unsigned long long ) ( ( address - prof->pr_off ) *
Packit 577717
									 prof->pr_scale );
Packit 577717
		indx = ( unsigned long ) ( lloffset >> 17 );
Packit 577717
	}
Packit 577717
Packit 577717
	/* confirm addresses within specified range */
Packit 577717
	if ( address >= prof->pr_off ) {
Packit 577717
		/* test first for 16-bit buckets; this should be the fast case */
Packit 577717
		if ( flags & PAPI_PROFIL_BUCKET_16 ) {
Packit 577717
			if ( ( indx * sizeof ( short ) ) < prof->pr_size ) {
Packit 577717
				buf16 = (unsigned short *) prof->pr_base;
Packit 577717
				buf16[indx] =
Packit 577717
					( unsigned short ) ( ( unsigned short ) buf16[indx] +
Packit 577717
										 profil_increment( buf16[indx], flags,
Packit 577717
														   excess,
Packit 577717
														   threshold ) );
Packit 577717
				PRFDBG( "posix_profil_16() bucket %lu = %u\n", indx,
Packit 577717
						buf16[indx] );
Packit 577717
			}
Packit 577717
		}
Packit 577717
		/* next, look for the 32-bit case */
Packit 577717
		else if ( flags & PAPI_PROFIL_BUCKET_32 ) {
Packit 577717
			if ( ( indx * sizeof ( int ) ) < prof->pr_size ) {
Packit 577717
				buf32 = (unsigned int *) prof->pr_base;
Packit 577717
				buf32[indx] = ( unsigned int ) buf32[indx] +
Packit 577717
					( unsigned int ) profil_increment( buf32[indx], flags,
Packit 577717
													   excess, threshold );
Packit 577717
				PRFDBG( "posix_profil_32() bucket %lu = %u\n", indx,
Packit 577717
						buf32[indx] );
Packit 577717
			}
Packit 577717
		}
Packit 577717
		/* finally, fall through to the 64-bit case */
Packit 577717
		else {
Packit 577717
			if ( ( indx * sizeof ( long long ) ) < prof->pr_size ) {
Packit 577717
				buf64 = (unsigned long long *) prof->pr_base;
Packit 577717
				buf64[indx] = ( unsigned long long ) buf64[indx] +
Packit 577717
					( unsigned long long ) profil_increment( ( long long )
Packit 577717
															 buf64[indx], flags,
Packit 577717
															 excess,
Packit 577717
															 threshold );
Packit 577717
				PRFDBG( "posix_profil_64() bucket %lu = %lld\n", indx,
Packit 577717
						buf64[indx] );
Packit 577717
			}
Packit 577717
		}
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
void
Packit 577717
_papi_hwi_dispatch_profile( EventSetInfo_t * ESI, caddr_t pc,
Packit 577717
							long long over, int profile_index )
Packit 577717
{
Packit 577717
	EventSetProfileInfo_t *profile = &ESI->profile;
Packit 577717
	PAPI_sprofil_t *sprof;
Packit 577717
	caddr_t offset = 0;
Packit 577717
	caddr_t best_offset = 0;
Packit 577717
	int count;
Packit 577717
	int best_index = -1;
Packit 577717
	int i;
Packit 577717
Packit 577717
	PRFDBG( "handled IP %p\n", pc );
Packit 577717
Packit 577717
	sprof = profile->prof[profile_index];
Packit 577717
	count = profile->count[profile_index];
Packit 577717
Packit 577717
	for ( i = 0; i < count; i++ ) {
Packit 577717
		offset = sprof[i].pr_off;
Packit 577717
		if ( ( offset < pc ) && ( offset > best_offset ) ) {
Packit 577717
			best_index = i;
Packit 577717
			best_offset = offset;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	if ( best_index == -1 )
Packit 577717
		best_index = 0;
Packit 577717
Packit 577717
	posix_profil( pc, &sprof[best_index], profile->flags, over,
Packit 577717
				  profile->threshold[profile_index] );
Packit 577717
}
Packit 577717
Packit 577717
/* if isHardware is true, then the processor is using hardware overflow,
Packit 577717
   else it is using software overflow. Use this parameter instead of 
Packit 577717
   _papi_hwi_system_info.supports_hw_overflow is in CRAY some processors
Packit 577717
   may use hardware overflow, some may use software overflow.
Packit 577717
Packit 577717
   overflow_bit: if the component can get the overflow bit when overflow
Packit 577717
                 occurs, then this should be passed by the component;
Packit 577717
Packit 577717
   If both genOverflowBit and isHardwareSupport are true, that means
Packit 577717
     the component doesn't know how to get the overflow bit from the
Packit 577717
     kernel directly, so we generate the overflow bit in this function 
Packit 577717
    since this function can access the ESI->overflow struct;
Packit 577717
   (The component can only set genOverflowBit parameter to true if the
Packit 577717
     hardware doesn't support multiple hardware overflow. If the
Packit 577717
     component supports multiple hardware overflow and you don't know how 
Packit 577717
     to get the overflow bit, then I don't know how to deal with this 
Packit 577717
     situation).
Packit 577717
*/
Packit 577717
Packit 577717
int
Packit 577717
_papi_hwi_dispatch_overflow_signal( void *papiContext, caddr_t address,
Packit 577717
				   int *isHardware, long long overflow_bit,
Packit 577717
				   int genOverflowBit, ThreadInfo_t ** t,
Packit 577717
				   int cidx )
Packit 577717
{
Packit 577717
	int retval, event_counter, i, overflow_flag, pos;
Packit 577717
	int papi_index, j;
Packit 577717
	int profile_index = 0;
Packit 577717
	long long overflow_vector;
Packit 577717
Packit 577717
	long long temp[_papi_hwd[cidx]->cmp_info.num_cntrs], over;
Packit 577717
	long long latest = 0;
Packit 577717
	ThreadInfo_t *thread;
Packit 577717
	EventSetInfo_t *ESI;
Packit 577717
	_papi_hwi_context_t *ctx = ( _papi_hwi_context_t * ) papiContext;
Packit 577717
Packit 577717
	OVFDBG( "enter\n" );
Packit 577717
Packit 577717
	if ( *t )
Packit 577717
		thread = *t;
Packit 577717
	else
Packit 577717
		*t = thread = _papi_hwi_lookup_thread( 0 );
Packit 577717
Packit 577717
	if ( thread != NULL ) {
Packit 577717
		ESI = thread->running_eventset[cidx];
Packit 577717
Packit 577717
		if ( ( ESI == NULL ) || ( ( ESI->state & PAPI_OVERFLOWING ) == 0 ) ) {
Packit 577717
			OVFDBG( "Either no eventset or eventset not set to overflow.\n" );
Packit 577717
#ifdef ANY_THREAD_GETS_SIGNAL
Packit 577717
			_papi_hwi_broadcast_signal( thread->tid );
Packit 577717
#endif
Packit 577717
			return ( PAPI_OK );
Packit 577717
		}
Packit 577717
Packit 577717
		if ( ESI->CmpIdx != cidx )
Packit 577717
			return ( PAPI_ENOCMP );
Packit 577717
Packit 577717
		if ( ESI->master != thread ) {
Packit 577717
			PAPIERROR
Packit 577717
				( "eventset->thread %#lx vs. current thread %#lx mismatch",
Packit 577717
				  ESI->master, thread );
Packit 577717
			return ( PAPI_EBUG );
Packit 577717
		}
Packit 577717
Packit 577717
		if ( isHardware ) {
Packit 577717
			if ( ESI->overflow.flags & PAPI_OVERFLOW_HARDWARE ) {
Packit 577717
				ESI->state |= PAPI_PAUSED;
Packit 577717
				*isHardware = 1;
Packit 577717
			} else
Packit 577717
				*isHardware = 0;
Packit 577717
		}
Packit 577717
		/* Get the latest counter value */
Packit 577717
		event_counter = ESI->overflow.event_counter;
Packit 577717
Packit 577717
		overflow_flag = 0;
Packit 577717
		overflow_vector = 0;
Packit 577717
Packit 577717
		if ( !( ESI->overflow.flags & PAPI_OVERFLOW_HARDWARE ) ) {
Packit 577717
			retval = _papi_hwi_read( thread->context[cidx], ESI, ESI->sw_stop );
Packit 577717
			if ( retval < PAPI_OK )
Packit 577717
				return ( retval );
Packit 577717
			for ( i = 0; i < event_counter; i++ ) {
Packit 577717
				papi_index = ESI->overflow.EventIndex[i];
Packit 577717
				latest = ESI->sw_stop[papi_index];
Packit 577717
				temp[i] = -1;
Packit 577717
Packit 577717
				if ( latest >= ( long long ) ESI->overflow.deadline[i] ) {
Packit 577717
					OVFDBG
Packit 577717
						( "dispatch_overflow() latest %lld, deadline %lld, threshold %d\n",
Packit 577717
						  latest, ESI->overflow.deadline[i],
Packit 577717
						  ESI->overflow.threshold[i] );
Packit 577717
					pos = ESI->EventInfoArray[papi_index].pos[0];
Packit 577717
					overflow_vector ^= ( long long ) 1 << pos;
Packit 577717
					temp[i] = latest - ESI->overflow.deadline[i];
Packit 577717
					overflow_flag = 1;
Packit 577717
					/* adjust the deadline */
Packit 577717
					ESI->overflow.deadline[i] =
Packit 577717
						latest + ESI->overflow.threshold[i];
Packit 577717
				}
Packit 577717
			}
Packit 577717
		} else if ( genOverflowBit ) {
Packit 577717
			/* we had assumed the overflow event can't be derived event */
Packit 577717
			papi_index = ESI->overflow.EventIndex[0];
Packit 577717
Packit 577717
			/* suppose the pos is the same as the counter number
Packit 577717
			 * (this is not true in Itanium, but itanium doesn't 
Packit 577717
			 * need us to generate the overflow bit
Packit 577717
			 */
Packit 577717
			pos = ESI->EventInfoArray[papi_index].pos[0];
Packit 577717
			overflow_vector = ( long long ) 1 << pos;
Packit 577717
		} else
Packit 577717
			overflow_vector = overflow_bit;
Packit 577717
Packit 577717
		if ( ( ESI->overflow.flags & PAPI_OVERFLOW_HARDWARE ) || overflow_flag ) {
Packit 577717
			if ( ESI->state & PAPI_PROFILING ) {
Packit 577717
				int k = 0;
Packit 577717
				while ( overflow_vector ) {
Packit 577717
					i = ffsll( overflow_vector ) - 1;
Packit 577717
					for ( j = 0; j < event_counter; j++ ) {
Packit 577717
						papi_index = ESI->overflow.EventIndex[j];
Packit 577717
						/* This loop is here ONLY because Pentium 4 can have tagged *
Packit 577717
						 * events that contain more than one counter without being  *
Packit 577717
						 * derived. You've gotta scan all terms to make sure you    *
Packit 577717
						 * find the one to profile. */
Packit 577717
						for ( k = 0, pos = 0; k < PAPI_EVENTS_IN_DERIVED_EVENT && pos >= 0;
Packit 577717
							  k++ ) {
Packit 577717
							pos = ESI->EventInfoArray[papi_index].pos[k];
Packit 577717
							if ( i == pos ) {
Packit 577717
								profile_index = j;
Packit 577717
								goto foundit;
Packit 577717
							}
Packit 577717
						}
Packit 577717
					}
Packit 577717
					if ( j == event_counter ) {
Packit 577717
						PAPIERROR
Packit 577717
							( "BUG! overflow_vector is 0, dropping interrupt" );
Packit 577717
						return ( PAPI_EBUG );
Packit 577717
					}
Packit 577717
Packit 577717
				  foundit:
Packit 577717
					if ( ( ESI->overflow.flags & PAPI_OVERFLOW_HARDWARE ) )
Packit 577717
						over = 0;
Packit 577717
					else
Packit 577717
						over = temp[profile_index];
Packit 577717
					_papi_hwi_dispatch_profile( ESI, address, over,
Packit 577717
												profile_index );
Packit 577717
					overflow_vector ^= ( long long ) 1 << i;
Packit 577717
				}
Packit 577717
				/* do not use overflow_vector after this place */
Packit 577717
			} else {
Packit 577717
				ESI->overflow.handler( ESI->EventSetIndex, ( void * ) address,
Packit 577717
									   overflow_vector, ctx->ucontext );
Packit 577717
			}
Packit 577717
		}
Packit 577717
		ESI->state &= ~( PAPI_PAUSED );
Packit 577717
	}
Packit 577717
#ifdef ANY_THREAD_GETS_SIGNAL
Packit 577717
	else {
Packit 577717
		OVFDBG( "I haven't been noticed by PAPI before\n" );
Packit 577717
		_papi_hwi_broadcast_signal( ( *_papi_hwi_thread_id_fn ) (  ) );
Packit 577717
	}
Packit 577717
#endif
Packit 577717
	return ( PAPI_OK );
Packit 577717
}
Packit 577717
Packit 577717
#include <sys/time.h>
Packit 577717
#include <errno.h>
Packit 577717
#include <string.h>
Packit 577717
Packit 577717
int _papi_hwi_using_signal[PAPI_NSIG];
Packit 577717
Packit 577717
int
Packit 577717
_papi_hwi_start_timer( int timer, int signal, int ns )
Packit 577717
{
Packit 577717
	struct itimerval value;
Packit 577717
	int us = ns / 1000;
Packit 577717
Packit 577717
	if ( us == 0 )
Packit 577717
		us = 1;
Packit 577717
Packit 577717
#ifdef ANY_THREAD_GETS_SIGNAL
Packit 577717
	_papi_hwi_lock( INTERNAL_LOCK );
Packit 577717
	if ( ( _papi_hwi_using_signal[signal] - 1 ) ) {
Packit 577717
		INTDBG( "itimer already installed\n" );
Packit 577717
		_papi_hwi_unlock( INTERNAL_LOCK );
Packit 577717
		return ( PAPI_OK );
Packit 577717
	}
Packit 577717
	_papi_hwi_unlock( INTERNAL_LOCK );
Packit 577717
#else
Packit 577717
	( void ) signal;		 /*unused */
Packit 577717
#endif
Packit 577717
Packit 577717
	value.it_interval.tv_sec = 0;
Packit 577717
	value.it_interval.tv_usec = us;
Packit 577717
	value.it_value.tv_sec = 0;
Packit 577717
	value.it_value.tv_usec = us;
Packit 577717
Packit 577717
	INTDBG( "Installing itimer %d, with %d us interval\n", timer, us );
Packit 577717
	if ( setitimer( timer, &value, NULL ) < 0 ) {
Packit 577717
		PAPIERROR( "setitimer errno %d", errno );
Packit 577717
		return ( PAPI_ESYS );
Packit 577717
	}
Packit 577717
Packit 577717
	return ( PAPI_OK );
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
_papi_hwi_start_signal( int signal, int need_context, int cidx )
Packit 577717
{
Packit 577717
	struct sigaction action;
Packit 577717
Packit 577717
	_papi_hwi_lock( INTERNAL_LOCK );
Packit 577717
	_papi_hwi_using_signal[signal]++;
Packit 577717
	if ( _papi_hwi_using_signal[signal] - 1 ) {
Packit 577717
		INTDBG( "_papi_hwi_using_signal is now %d\n",
Packit 577717
				_papi_hwi_using_signal[signal] );
Packit 577717
		_papi_hwi_unlock( INTERNAL_LOCK );
Packit 577717
		return ( PAPI_OK );
Packit 577717
	}
Packit 577717
Packit 577717
	memset( &action, 0x00, sizeof ( struct sigaction ) );
Packit 577717
	action.sa_flags = SA_RESTART;
Packit 577717
	action.sa_sigaction =
Packit 577717
		( void ( * )( int, siginfo_t *, void * ) ) _papi_hwd[cidx]->
Packit 577717
		dispatch_timer;
Packit 577717
	if ( need_context )
Packit 577717
#if (defined(_BGL) /*|| defined (__bgp__)*/)
Packit 577717
		action.sa_flags |= SIGPWR;
Packit 577717
#else
Packit 577717
		action.sa_flags |= SA_SIGINFO;
Packit 577717
#endif
Packit 577717
Packit 577717
	INTDBG( "installing signal handler\n" );
Packit 577717
	if ( sigaction( signal, &action, NULL ) < 0 ) {
Packit 577717
		PAPIERROR( "sigaction errno %d", errno );
Packit 577717
		_papi_hwi_unlock( INTERNAL_LOCK );
Packit 577717
		return ( PAPI_ESYS );
Packit 577717
	}
Packit 577717
Packit 577717
	INTDBG( "_papi_hwi_using_signal[%d] is now %d.\n", signal,
Packit 577717
			_papi_hwi_using_signal[signal] );
Packit 577717
	_papi_hwi_unlock( INTERNAL_LOCK );
Packit 577717
Packit 577717
	return ( PAPI_OK );
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
_papi_hwi_stop_signal( int signal )
Packit 577717
{
Packit 577717
	_papi_hwi_lock( INTERNAL_LOCK );
Packit 577717
	if ( --_papi_hwi_using_signal[signal] == 0 ) {
Packit 577717
		INTDBG( "removing signal handler\n" );
Packit 577717
		if ( sigaction( signal, NULL, NULL ) == -1 ) {
Packit 577717
			PAPIERROR( "sigaction errno %d", errno );
Packit 577717
			_papi_hwi_unlock( INTERNAL_LOCK );
Packit 577717
			return ( PAPI_ESYS );
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	INTDBG( "_papi_hwi_using_signal[%d] is now %d\n", signal,
Packit 577717
			_papi_hwi_using_signal[signal] );
Packit 577717
	_papi_hwi_unlock( INTERNAL_LOCK );
Packit 577717
Packit 577717
	return ( PAPI_OK );
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
_papi_hwi_stop_timer( int timer, int signal )
Packit 577717
{
Packit 577717
	struct itimerval value;
Packit 577717
Packit 577717
#ifdef ANY_THREAD_GETS_SIGNAL
Packit 577717
	_papi_hwi_lock( INTERNAL_LOCK );
Packit 577717
	if ( _papi_hwi_using_signal[signal] > 1 ) {
Packit 577717
		INTDBG( "itimer in use by another thread\n" );
Packit 577717
		_papi_hwi_unlock( INTERNAL_LOCK );
Packit 577717
		return ( PAPI_OK );
Packit 577717
	}
Packit 577717
	_papi_hwi_unlock( INTERNAL_LOCK );
Packit 577717
#else
Packit 577717
	( void ) signal;		 /*unused */
Packit 577717
#endif
Packit 577717
Packit 577717
	value.it_interval.tv_sec = 0;
Packit 577717
	value.it_interval.tv_usec = 0;
Packit 577717
	value.it_value.tv_sec = 0;
Packit 577717
	value.it_value.tv_usec = 0;
Packit 577717
Packit 577717
	INTDBG( "turning off timer\n" );
Packit 577717
	if ( setitimer( timer, &value, NULL ) == -1 ) {
Packit 577717
		PAPIERROR( "setitimer errno %d", errno );
Packit 577717
		return PAPI_ESYS;
Packit 577717
	}
Packit 577717
Packit 577717
	return PAPI_OK;
Packit 577717
}
Packit 577717
Packit 577717
Packit 577717
Packit 577717
#if (!defined(HAVE_FFSLL) || defined(__bgp__))
Packit 577717
/* find the first set bit in long long */
Packit 577717
Packit 577717
int
Packit 577717
ffsll( long long lli )
Packit 577717
{
Packit 577717
	int i, num, t, tmpint, len;
Packit 577717
Packit 577717
	num = sizeof ( long long ) / sizeof ( int );
Packit 577717
	if ( num == 1 )
Packit 577717
		return ( ffs( ( int ) lli ) );
Packit 577717
	len = sizeof ( int ) * CHAR_BIT;
Packit 577717
Packit 577717
	for ( i = 0; i < num; i++ ) {
Packit 577717
		tmpint = ( int ) ( ( ( lli >> len ) << len ) ^ lli );
Packit 577717
Packit 577717
		t = ffs( tmpint );
Packit 577717
		if ( t ) {
Packit 577717
			return ( t + i * len );
Packit 577717
		}
Packit 577717
		lli = lli >> len;
Packit 577717
	}
Packit 577717
	return PAPI_OK;
Packit 577717
}
Packit 577717
#endif