PAPI  5.0.1.0
papi_bipartite.h
Go to the documentation of this file.
00001 /*
00002 * File:    papi_bipartite.h
00003 * Author:  Dan Terpstra
00004 *          terpstra@eecs.utk.edu
00005 * Mods:    
00006 *          
00007 */
00008 /* This file contains one function: _papi_bipartite_alloc()
00009    Its role is to act as an execution harness for implementing a recursive
00010    Modified Bipartite Graph allocation of counter resources for those
00011    platforms that don't have built-in smart counter allocation.
00012    It is intended to be #included in the cpu component source to minimize
00013    other disruption to the build process.
00014    
00015    This routine presumes the existence of a half dozen "bpt_" helper routines. 
00016    Prototypes for these routines are given below.
00017  
00018     success  return 1
00019     fail     return 0
00020 */
00021 
00022 /* This function examines the event to determine
00023     if it can be mapped to counter ctr.
00024     Returns true if it can, false if it can't. */
00025 static int
00026 _bpt_map_avail( hwd_reg_alloc_t * dst, int ctr );
00027 
00028 /* This function forces the event to
00029     be mapped to only counter ctr.
00030     Returns nothing.  */
00031 static void
00032 _bpt_map_set( hwd_reg_alloc_t * dst, int ctr );
00033 
00034 /* This function examines the event to determine
00035    if it has a single exclusive mapping.
00036    Returns true if exlusive, false if non-exclusive.  */
00037 static int
00038 _bpt_map_exclusive( hwd_reg_alloc_t * dst );
00039 
00040 /* This function compares the dst and src events
00041     to determine if any resources are shared. Typically the src event
00042     is exclusive, so this detects a conflict if true.
00043     Returns true if conflict, false if no conflict.  */
00044 static int
00045 _bpt_map_shared( hwd_reg_alloc_t * dst, hwd_reg_alloc_t * src );
00046 
00047 /* This function removes shared resources available to the src event
00048     from the resources available to the dst event,
00049     and reduces the rank of the dst event accordingly. Typically,
00050     the src event will be exclusive, but the code shouldn't assume it.
00051     Returns nothing.  */
00052 static void
00053 _bpt_map_preempt( hwd_reg_alloc_t * dst, hwd_reg_alloc_t * src );
00054 
00055 static void
00056 _bpt_map_update( hwd_reg_alloc_t * dst, hwd_reg_alloc_t * src );
00057 
00058 
00059 static int
00060 _papi_bipartite_alloc( hwd_reg_alloc_t * event_list, int count, int cidx )
00061 {
00062     int i, j;
00063     char *ptr = ( char * ) event_list;
00064     int idx_q[count];                  /* queue of indexes of lowest rank events */
00065     int map_q[count];                  /* queue of mapped events (TRUE if mapped) */
00066     int head, tail;
00067     int size = _papi_hwd[cidx]->size.reg_alloc;
00068 
00069     /* build a queue of indexes to all events 
00070        that live on one counter only (rank == 1) */
00071     head = 0;                /* points to top of queue */
00072     tail = 0;                /* points to bottom of queue */
00073     for ( i = 0; i < count; i++ ) {
00074         map_q[i] = 0;
00075         if ( _bpt_map_exclusive( ( hwd_reg_alloc_t * ) & ptr[size * i] ) )
00076             idx_q[tail++] = i;
00077     }
00078     /* scan the single counter queue looking for events that share counters.
00079        If two events can live only on one counter, return failure.
00080        If the second event lives on more than one counter, remove shared counter
00081        from its selector and reduce its rank. 
00082        Mark first event as mapped to its counter. */
00083     while ( head < tail ) {
00084         for ( i = 0; i < count; i++ ) {
00085             if ( i != idx_q[head] ) {
00086                 if ( _bpt_map_shared( ( hwd_reg_alloc_t * ) & ptr[size * i],
00087                                      ( hwd_reg_alloc_t * ) & ptr[size *
00088                                                                  idx_q
00089                                                                  [head]] ) ) {
00090                     /* both share a counter; if second is exclusive, mapping fails */
00091                     if ( _bpt_map_exclusive( ( hwd_reg_alloc_t * ) &
00092                                             ptr[size * i] ) )
00093                         return 0;
00094                     else {
00095                         _bpt_map_preempt( ( hwd_reg_alloc_t * ) &
00096                                              ptr[size * i],
00097                                              ( hwd_reg_alloc_t * ) & ptr[size *
00098                                                                          idx_q
00099                                                                          [head]] );
00100                         if ( _bpt_map_exclusive( ( hwd_reg_alloc_t * ) &
00101                                                 ptr[size * i] ) )
00102                             idx_q[tail++] = i;
00103                     }
00104                 }
00105             }
00106         }
00107         map_q[idx_q[head]] = 1; /* mark this event as mapped */
00108         head++;
00109     }
00110     if ( tail == count ) {
00111         return 1;            /* idx_q includes all events; everything is successfully mapped */
00112     } else {
00113         char *rest_event_list;
00114         char *copy_rest_event_list;
00115         int remainder;
00116 
00117         rest_event_list =
00118             papi_calloc(  _papi_hwd[cidx]->cmp_info.num_cntrs, 
00119                       size );
00120 
00121         copy_rest_event_list =
00122                 papi_calloc( _papi_hwd[cidx]->cmp_info.num_cntrs,
00123                      size );
00124 
00125         if ( !rest_event_list || !copy_rest_event_list ) {
00126             if ( rest_event_list )
00127                 papi_free( rest_event_list );
00128             if ( copy_rest_event_list )
00129                 papi_free( copy_rest_event_list );
00130             return ( 0 );
00131         }
00132 
00133         /* copy all unmapped events to a second list and make a backup */
00134         for ( i = 0, j = 0; i < count; i++ ) {
00135             if ( map_q[i] == 0 ) {
00136                 memcpy( &copy_rest_event_list[size * j++], &ptr[size * i],
00137                         ( size_t ) size );
00138             }
00139         }
00140         remainder = j;
00141 
00142         memcpy( rest_event_list, copy_rest_event_list,
00143                 ( size_t ) size * ( size_t ) remainder );
00144 
00145         /* try each possible mapping until you fail or find one that works */
00146         for ( i = 0; i < _papi_hwd[cidx]->cmp_info.num_cntrs; i++ ) {
00147             /* for the first unmapped event, try every possible counter */
00148             if ( _bpt_map_avail( ( hwd_reg_alloc_t * ) rest_event_list, i ) ) {
00149                  _bpt_map_set( ( hwd_reg_alloc_t * ) rest_event_list, i );
00150                 /* remove selected counter from all other unmapped events */
00151                 for ( j = 1; j < remainder; j++ ) {
00152                     if ( _bpt_map_shared( ( hwd_reg_alloc_t * ) &
00153                                          rest_event_list[size * j],
00154                                          ( hwd_reg_alloc_t * )
00155                                          rest_event_list ) )
00156                         _bpt_map_preempt( ( hwd_reg_alloc_t * ) &
00157                                              rest_event_list[size * j],
00158                                              ( hwd_reg_alloc_t * )
00159                                              rest_event_list );
00160                 }
00161                 /* if recursive call to allocation works, break out of the loop */
00162                 if ( _papi_bipartite_alloc
00163                      ( ( hwd_reg_alloc_t * ) rest_event_list, remainder,
00164                        cidx ) )
00165                     break;
00166 
00167                 /* recursive mapping failed; copy the backup list and try the next combination */
00168                 memcpy( rest_event_list, copy_rest_event_list,
00169                         ( size_t ) size * ( size_t ) remainder );
00170             }
00171         }
00172         if ( i == _papi_hwd[cidx]->cmp_info.num_cntrs ) {
00173             papi_free( rest_event_list );
00174             papi_free( copy_rest_event_list );
00175             return 0;        /* fail to find mapping */
00176         }
00177         for ( i = 0, j = 0; i < count; i++ ) {
00178             if ( map_q[i] == 0 )
00179                 _bpt_map_update( ( hwd_reg_alloc_t * ) & ptr[size * i],
00180                                     ( hwd_reg_alloc_t * ) & rest_event_list[size
00181                                                                             *
00182                                                                             j++] );
00183         }
00184         papi_free( rest_event_list );
00185         papi_free( copy_rest_event_list );
00186         return 1;
00187     }
00188 }
00189 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines