|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* File: prof_utils.c
|
|
Packit |
577717 |
* Author: Dan Terpstra
|
|
Packit |
577717 |
* terpstra@cs.utk.edu
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* This file contains utility functions useful for all profiling tests
|
|
Packit |
577717 |
It can be used by:
|
|
Packit |
577717 |
- profile.c,
|
|
Packit |
577717 |
- sprofile.c,
|
|
Packit |
577717 |
- profile_pthreads.c,
|
|
Packit |
577717 |
- profile_twoevents.c,
|
|
Packit |
577717 |
- earprofile.c,
|
|
Packit |
577717 |
- future profiling tests.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include <stdio.h>
|
|
Packit |
577717 |
#include <stdlib.h>
|
|
Packit |
577717 |
#include <string.h>
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include "papi.h"
|
|
Packit |
577717 |
#include "papi_test.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include "do_loops.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#include "prof_utils.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* variables global to profiling tests */
|
|
Packit |
577717 |
long long **values;
|
|
Packit |
577717 |
char event_name[PAPI_MAX_STR_LEN];
|
|
Packit |
577717 |
int PAPI_event;
|
|
Packit |
577717 |
int EventSet = PAPI_NULL;
|
|
Packit |
577717 |
void *profbuf[5];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Many profiling tests count one of {FP_INS, FP_OPS, TOT_INS} and TOT_CYC.
|
|
Packit |
577717 |
This function creates an event set containing the appropriate pair of events.
|
|
Packit |
577717 |
It also initializes the global event_name string to the event selected.
|
|
Packit |
577717 |
Assumed globals: EventSet, PAPI_event, event_name.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
int
|
|
Packit |
577717 |
prof_events( int num_tests)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int retval;
|
|
Packit |
577717 |
int num_events, mask;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* add PAPI_TOT_CYC and one of the events in PAPI_FP_INS, PAPI_FP_OPS or
|
|
Packit |
577717 |
PAPI_TOT_INS, depends on the availability of the event on the
|
|
Packit |
577717 |
platform */
|
|
Packit |
577717 |
EventSet = add_two_nonderived_events( &num_events, &PAPI_event, &mask );
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (num_events==0) {
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
values = allocate_test_space( num_tests, num_events );
|
|
Packit |
577717 |
|
|
Packit |
577717 |
retval = PAPI_event_code_to_name( PAPI_event, event_name );
|
|
Packit |
577717 |
if (retval != PAPI_OK ) {
|
|
Packit |
577717 |
test_fail( __FILE__, __LINE__, "PAPI_event_code_to_name", retval );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return mask;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* This function displays info from the prginfo structure in a standardized format.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
prof_print_address( const char *title, const PAPI_exe_info_t * prginfo )
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
printf( "%s\n", title );
|
|
Packit |
577717 |
printf
|
|
Packit |
577717 |
( "----------------------------------------------------------------\n" );
|
|
Packit |
577717 |
printf( "Text start: %p, Text end: %p, Text length: %#x\n",
|
|
Packit |
577717 |
prginfo->address_info.text_start, prginfo->address_info.text_end,
|
|
Packit |
577717 |
( unsigned int ) ( prginfo->address_info.text_end -
|
|
Packit |
577717 |
prginfo->address_info.text_start ) );
|
|
Packit |
577717 |
printf( "Data start: %p, Data end: %p\n", prginfo->address_info.data_start,
|
|
Packit |
577717 |
prginfo->address_info.data_end );
|
|
Packit |
577717 |
printf( "BSS start : %p, BSS end : %p\n", prginfo->address_info.bss_start,
|
|
Packit |
577717 |
prginfo->address_info.bss_end );
|
|
Packit |
577717 |
|
|
Packit |
577717 |
printf
|
|
Packit |
577717 |
( "----------------------------------------------------------------\n" );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* This function displays profining information useful for several profile tests.
|
|
Packit |
577717 |
It (probably inappropriately) assumes use of a common THRESHOLD. This should
|
|
Packit |
577717 |
probably be a passed parameter.
|
|
Packit |
577717 |
Assumed globals: event_name, start, stop.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
prof_print_prof_info( caddr_t start, caddr_t end, int threshold,
|
|
Packit |
577717 |
char *event_name )
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
printf( "Profiling event : %s\n", event_name );
|
|
Packit |
577717 |
printf( "Profile Threshold: %d\n", threshold );
|
|
Packit |
577717 |
printf( "Profile Iters : %d\n",
|
|
Packit |
577717 |
( getenv( "NUM_ITERS" ) ? atoi( getenv( "NUM_ITERS" ) ) :
|
|
Packit |
577717 |
NUM_ITERS ) );
|
|
Packit |
577717 |
printf( "Profile Range : %p to %p\n", start, end );
|
|
Packit |
577717 |
printf
|
|
Packit |
577717 |
( "----------------------------------------------------------------\n" );
|
|
Packit |
577717 |
printf( "\n" );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Most profile tests begin by counting the eventset with no profiling enabled.
|
|
Packit |
577717 |
This function does that work. It assumes that the 'work' routine is do_both().
|
|
Packit |
577717 |
A better implementation would pass a pointer to the work function.
|
|
Packit |
577717 |
Assumed globals: EventSet, values, event_name.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
do_no_profile( int quiet )
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int retval;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if ( ( retval = PAPI_start( EventSet ) ) != PAPI_OK )
|
|
Packit |
577717 |
test_fail( __FILE__, __LINE__, "PAPI_start", retval );
|
|
Packit |
577717 |
|
|
Packit |
577717 |
do_flops( getenv( "NUM_ITERS" ) ? atoi( getenv( "NUM_ITERS" ) ) :
|
|
Packit |
577717 |
NUM_ITERS );
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if ( ( retval = PAPI_stop( EventSet, values[0] ) ) != PAPI_OK )
|
|
Packit |
577717 |
test_fail( __FILE__, __LINE__, "PAPI_stop", retval );
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!quiet) {
|
|
Packit |
577717 |
printf( "Test type : \t%s\n", "No profiling" );
|
|
Packit |
577717 |
printf( TAB1, event_name, ( values[0] )[0] );
|
|
Packit |
577717 |
printf( TAB1, "PAPI_TOT_CYC", ( values[0] )[1] );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* This routine allocates and initializes up to 5 equal sized profiling buffers.
|
|
Packit |
577717 |
They need to be freed when profiling is completed.
|
|
Packit |
577717 |
The number and size are passed parameters.
|
|
Packit |
577717 |
The profbuf[] array of void * pointers is an assumed global.
|
|
Packit |
577717 |
It should be cast to the required type by the parent routine.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
prof_alloc( int num, unsigned long blength )
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for ( i = 0; i < num; i++ ) {
|
|
Packit |
577717 |
profbuf[i] = malloc( blength );
|
|
Packit |
577717 |
if ( profbuf[i] == NULL ) {
|
|
Packit |
577717 |
test_fail( __FILE__, __LINE__, "malloc", PAPI_ESYS );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
memset( profbuf[i], 0x00, blength );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Given the profiling type (16, 32, or 64) this function returns the
|
|
Packit |
577717 |
bucket size in bytes. NOTE: the bucket size does not ALWAYS correspond
|
|
Packit |
577717 |
to the expected value, esp on architectures like Cray with weird data types.
|
|
Packit |
577717 |
This is necessary because the posix_profile routine in extras.c relies on
|
|
Packit |
577717 |
the data types and sizes produced by the compiler.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
int
|
|
Packit |
577717 |
prof_buckets( int bucket )
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int bucket_size;
|
|
Packit |
577717 |
switch ( bucket ) {
|
|
Packit |
577717 |
case PAPI_PROFIL_BUCKET_16:
|
|
Packit |
577717 |
bucket_size = sizeof ( short );
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PAPI_PROFIL_BUCKET_32:
|
|
Packit |
577717 |
bucket_size = sizeof ( int );
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PAPI_PROFIL_BUCKET_64:
|
|
Packit |
577717 |
bucket_size = sizeof ( unsigned long long );
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
bucket_size = 0;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return ( bucket_size );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* A standardized header printing routine. No assumed globals.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
prof_head( unsigned long blength, int bucket, int num_buckets, const char *header )
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int bucket_size = prof_buckets( bucket );
|
|
Packit |
577717 |
printf
|
|
Packit |
577717 |
( "\n------------------------------------------------------------\n" );
|
|
Packit |
577717 |
printf( "PAPI_profil() hash table, Bucket size: %d bits.\n",
|
|
Packit |
577717 |
bucket_size * 8 );
|
|
Packit |
577717 |
printf( "Number of buckets: %d.\nLength of buffer: %ld bytes.\n",
|
|
Packit |
577717 |
num_buckets, blength );
|
|
Packit |
577717 |
printf( "------------------------------------------------------------\n" );
|
|
Packit |
577717 |
printf( "%s\n", header );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* This function prints a standardized profile output based on the bucket size.
|
|
Packit |
577717 |
A row consisting of an address and 'n' data elements is displayed for each
|
|
Packit |
577717 |
address with at least one non-zero bucket.
|
|
Packit |
577717 |
Assumes global profbuf[] array pointers.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
void
|
|
Packit |
577717 |
prof_out( caddr_t start, int n, int bucket, int num_buckets,
|
|
Packit |
577717 |
unsigned int scale )
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int i, j;
|
|
Packit |
577717 |
unsigned short buf_16;
|
|
Packit |
577717 |
unsigned int buf_32;
|
|
Packit |
577717 |
unsigned long long buf_64;
|
|
Packit |
577717 |
unsigned short **buf16 = ( unsigned short ** ) profbuf;
|
|
Packit |
577717 |
unsigned int **buf32 = ( unsigned int ** ) profbuf;
|
|
Packit |
577717 |
unsigned long long **buf64 = ( unsigned long long ** ) profbuf;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if ( !TESTS_QUIET ) {
|
|
Packit |
577717 |
/* printf("%#lx\n",(unsigned long) start + (unsigned long) (2 * i)); */
|
|
Packit |
577717 |
/* printf("start: %p; i: %#x; scale: %#x; i*scale: %#x; i*scale >>15: %#x\n", start, i, scale, i*scale, (i*scale)>>15); */
|
|
Packit |
577717 |
switch ( bucket ) {
|
|
Packit |
577717 |
case PAPI_PROFIL_BUCKET_16:
|
|
Packit |
577717 |
for ( i = 0; i < num_buckets; i++ ) {
|
|
Packit |
577717 |
for ( j = 0, buf_16 = 0; j < n; j++ )
|
|
Packit |
577717 |
buf_16 |= ( buf16[j] )[i];
|
|
Packit |
577717 |
if ( buf_16 ) {
|
|
Packit |
577717 |
/* On 32bit builds with gcc 4.3 gcc complained about casting caddr_t => long long
|
|
Packit |
577717 |
* Thus the unsigned long to long long cast */
|
|
Packit |
577717 |
printf( "%#-16llx",
|
|
Packit |
577717 |
(long long) (unsigned long)start +
|
|
Packit |
577717 |
( ( ( long long ) i * scale ) >> 15 ) );
|
|
Packit |
577717 |
for ( j = 0, buf_16 = 0; j < n; j++ )
|
|
Packit |
577717 |
printf( "\t%d", ( buf16[j] )[i] );
|
|
Packit |
577717 |
printf( "\n" );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PAPI_PROFIL_BUCKET_32:
|
|
Packit |
577717 |
for ( i = 0; i < num_buckets; i++ ) {
|
|
Packit |
577717 |
for ( j = 0, buf_32 = 0; j < n; j++ )
|
|
Packit |
577717 |
buf_32 |= ( buf32[j] )[i];
|
|
Packit |
577717 |
if ( buf_32 ) {
|
|
Packit |
577717 |
printf( "%#-16llx",
|
|
Packit |
577717 |
(long long) (unsigned long)start +
|
|
Packit |
577717 |
( ( ( long long ) i * scale ) >> 15 ) );
|
|
Packit |
577717 |
for ( j = 0, buf_32 = 0; j < n; j++ )
|
|
Packit |
577717 |
printf( "\t%d", ( buf32[j] )[i] );
|
|
Packit |
577717 |
printf( "\n" );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PAPI_PROFIL_BUCKET_64:
|
|
Packit |
577717 |
for ( i = 0; i < num_buckets; i++ ) {
|
|
Packit |
577717 |
for ( j = 0, buf_64 = 0; j < n; j++ )
|
|
Packit |
577717 |
buf_64 |= ( buf64[j] )[i];
|
|
Packit |
577717 |
if ( buf_64 ) {
|
|
Packit |
577717 |
printf( "%#-16llx",
|
|
Packit |
577717 |
(long long) (unsigned long)start +
|
|
Packit |
577717 |
( ( ( long long ) i * scale ) >> 15 ) );
|
|
Packit |
577717 |
for ( j = 0, buf_64 = 0; j < n; j++ )
|
|
Packit |
577717 |
printf( "\t%lld", ( buf64[j] )[i] );
|
|
Packit |
577717 |
printf( "\n" );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
printf
|
|
Packit |
577717 |
( "------------------------------------------------------------\n\n" );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* This function checks to make sure that some buffer value somewhere is nonzero.
|
|
Packit |
577717 |
If all buffers are empty, zero is returned. This usually indicates a profiling
|
|
Packit |
577717 |
failure. Assumes global profbuf[].
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
int
|
|
Packit |
577717 |
prof_check( int n, int bucket, int num_buckets )
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int i, j;
|
|
Packit |
577717 |
int retval = 0;
|
|
Packit |
577717 |
unsigned short **buf16 = ( unsigned short ** ) profbuf;
|
|
Packit |
577717 |
unsigned int **buf32 = ( unsigned int ** ) profbuf;
|
|
Packit |
577717 |
unsigned long long **buf64 = ( unsigned long long ** ) profbuf;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
switch ( bucket ) {
|
|
Packit |
577717 |
case PAPI_PROFIL_BUCKET_16:
|
|
Packit |
577717 |
for ( i = 0; i < num_buckets; i++ )
|
|
Packit |
577717 |
for ( j = 0; j < n; j++ )
|
|
Packit |
577717 |
retval = retval || buf16[j][i];
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PAPI_PROFIL_BUCKET_32:
|
|
Packit |
577717 |
for ( i = 0; i < num_buckets; i++ )
|
|
Packit |
577717 |
for ( j = 0; j < n; j++ )
|
|
Packit |
577717 |
retval = retval || buf32[j][i];
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case PAPI_PROFIL_BUCKET_64:
|
|
Packit |
577717 |
for ( i = 0; i < num_buckets; i++ )
|
|
Packit |
577717 |
for ( j = 0; j < n; j++ )
|
|
Packit |
577717 |
retval = retval || buf64[j][i];
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return ( retval );
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Computes the length (in bytes) of the buffer required for profiling.
|
|
Packit |
577717 |
'plength' is the profile length, or address range to be profiled.
|
|
Packit |
577717 |
By convention, it is assumed that there are half as many buckets as addresses.
|
|
Packit |
577717 |
The scale factor is a fixed point fraction in which 0xffff = ~1
|
|
Packit |
577717 |
0x8000 = 1/2
|
|
Packit |
577717 |
0x4000 = 1/4, etc.
|
|
Packit |
577717 |
Thus, the number of profile buckets is (plength/2) * (scale/65536),
|
|
Packit |
577717 |
and the length (in bytes) of the profile buffer is buckets * bucket size.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
unsigned long
|
|
Packit |
577717 |
prof_size( unsigned long plength, unsigned scale, int bucket, int *num_buckets )
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned long blength;
|
|
Packit |
577717 |
long long llength = ( ( long long ) plength * scale );
|
|
Packit |
577717 |
int bucket_size = prof_buckets( bucket );
|
|
Packit |
577717 |
*num_buckets = ( int ) ( llength / 65536 / 2 );
|
|
Packit |
577717 |
blength = ( unsigned long ) ( *num_buckets * bucket_size );
|
|
Packit |
577717 |
return ( blength );
|
|
Packit |
577717 |
}
|