PAPI  5.3.0.0
linux-lustre.c
Go to the documentation of this file.
00001 /****************************/
00002 /* THIS IS OPEN SOURCE CODE */
00003 /****************************/
00004 
00016 #include <string.h>
00017 #include <sys/types.h>
00018 #include <sys/stat.h>
00019 #include <fcntl.h>
00020 #include <dirent.h>
00021 #include <stdint.h>
00022 #include <ctype.h>
00023 
00024 #include "papi.h"
00025 #include "papi_internal.h"
00026 #include "papi_vector.h"
00027 #include "papi_memory.h"
00028 
00030 typedef struct counter_info_struct
00031 {
00032     int idx;
00033     char *name;
00034     char *description;
00035     char *unit;
00036     unsigned long long value;
00037 } counter_info;
00038 
00039 typedef struct
00040 {
00041     int count;
00042     char **data;
00043 } string_list;
00044 
00045 
00047 typedef struct lustre_fs_struct
00048 {
00049     char *proc_file;
00050     char *proc_file_readahead;
00051     counter_info *write_cntr;
00052     counter_info *read_cntr;
00053     counter_info *readahead_cntr;
00054     struct lustre_fs_struct *next;
00055 } lustre_fs;
00056 
00057 #define LUSTRE_MAX_COUNTERS 100
00058 #define LUSTRE_MAX_COUNTER_TERMS  LUSTRE_MAX_COUNTERS
00059 
00060 typedef counter_info LUSTRE_register_t;
00061 typedef counter_info LUSTRE_native_event_entry_t;
00062 typedef counter_info LUSTRE_reg_alloc_t;
00063 
00064 
00065 typedef struct LUSTRE_control_state
00066 {
00067     long long start_count[LUSTRE_MAX_COUNTERS];
00068         long long current_count[LUSTRE_MAX_COUNTERS];
00069         long long difference[LUSTRE_MAX_COUNTERS];
00070         int which_counter[LUSTRE_MAX_COUNTERS];
00071     int num_events;
00072 } LUSTRE_control_state_t;
00073 
00074 
00075 typedef struct LUSTRE_context
00076 {
00077     LUSTRE_control_state_t state;
00078 } LUSTRE_context_t;
00079 
00080 /* Default path to lustre stats */
00081 #ifdef FAKE_LUSTRE
00082 const char proc_base_path[] = "./components/lustre/fake_proc/fs/lustre/";
00083 #else
00084 const char proc_base_path[] = "/proc/fs/lustre/";
00085 #endif
00086 
00087 static counter_info **lustre_native_table = NULL;
00088 static int num_events = 0;
00089 static int table_size = 32;
00090 
00091 /* mount Lustre fs are kept in a list */
00092 static lustre_fs *root_lustre_fs = NULL;
00093 
00094 papi_vector_t _lustre_vector;
00095 
00096 /******************************************************************************
00097  ********  BEGIN FUNCTIONS  USED INTERNALLY SPECIFIC TO THIS COMPONENT ********
00098  *****************************************************************************/
00099 static int resize_native_table() {
00100     counter_info** new_table;
00101     int new_size = table_size*2;
00102     new_table = (counter_info**)papi_malloc(sizeof(counter_info*) * new_size);
00103     if (NULL==new_table)
00104         return PAPI_ENOMEM;
00105     if ( lustre_native_table) {
00106         memcpy(new_table, lustre_native_table, sizeof(counter_info*) * table_size );
00107         papi_free(lustre_native_table);
00108     }
00109     lustre_native_table = new_table;
00110     table_size*=2;
00111     return PAPI_OK;
00112 }
00113 
00120 static counter_info *
00121 addCounter( const char *name, const char *desc, const char *unit )
00122 {
00123     counter_info *cntr;
00124 
00125     if ( num_events >= table_size )
00126         if (PAPI_OK != resize_native_table())
00127             return NULL;
00128 
00129     cntr = malloc( sizeof ( counter_info ) );
00130 
00131     if ( cntr == NULL ) {
00132        SUBDBG("can not allocate memory for new counter\n" );
00133        return NULL;
00134     }
00135 
00136     cntr->idx=num_events;
00137     cntr->name = strdup( name );
00138     cntr->description = strdup( desc );
00139     cntr->unit = strdup( unit );
00140     cntr->value = 0;
00141 
00142     lustre_native_table[num_events]=cntr;
00143 
00144     num_events++;
00145 
00146     return cntr;
00147 }
00148 
00155 static int
00156 addLustreFS( const char *name,
00157          const char *procpath_general, 
00158          const char *procpath_readahead )
00159 {
00160     lustre_fs *fs, *last;
00161     char counter_name[512];
00162     FILE *fff;
00163 
00164     SUBDBG("Adding lustre fs\n");
00165 
00166     fs = malloc( sizeof ( lustre_fs ) );
00167     if ( fs == NULL ) {
00168        SUBDBG("can not allocate memory for new Lustre FS description\n" );
00169        return PAPI_ENOMEM;
00170     }
00171 
00172     fs->proc_file=strdup(procpath_general);
00173     fff = fopen( procpath_general, "r" );
00174     if ( fff == NULL ) {
00175       SUBDBG("can not open '%s'\n", procpath_general );
00176       free(fs);
00177       return PAPI_ESYS;
00178     }
00179     fclose(fff);
00180 
00181     fs->proc_file_readahead = strdup(procpath_readahead);
00182     fff = fopen( procpath_readahead, "r" );
00183     if ( fff == NULL ) {
00184       SUBDBG("can not open '%s'\n", procpath_readahead );
00185       free(fs);
00186       return PAPI_ESYS;
00187     }
00188     fclose(fff);
00189 
00190     sprintf( counter_name, "%s_llread", name );
00191     if (NULL == (fs->read_cntr = addCounter( counter_name, 
00192                     "bytes read on this lustre client", 
00193                     "bytes" ))) {
00194             free(fs);
00195             return PAPI_ENOMEM;
00196     }
00197 
00198     sprintf( counter_name, "%s_llwrite", name );
00199     if ( NULL == (fs->write_cntr = addCounter( counter_name, 
00200                      "bytes written on this lustre client",
00201                      "bytes" ))) {
00202             free(fs->read_cntr);
00203             free(fs);
00204             return PAPI_ENOMEM;
00205     }
00206 
00207     sprintf( counter_name, "%s_wrong_readahead", name );
00208     if ( NULL == (fs->readahead_cntr = addCounter( counter_name, 
00209                      "bytes read but discarded due to readahead",
00210                      "bytes" ))) {
00211             free(fs->read_cntr);
00212             free(fs->write_cntr);
00213             free(fs);
00214             return PAPI_ENOMEM;
00215     }
00216 
00217     fs->next = NULL;
00218 
00219     /* Insert into the linked list */
00220     /* Does this need locking? */
00221     if ( root_lustre_fs == NULL ) {
00222         root_lustre_fs = fs;
00223     } else {
00224         last = root_lustre_fs;
00225 
00226         while ( last->next != NULL )
00227             last = last->next;
00228 
00229         last->next = fs;
00230     }
00231     return PAPI_OK;
00232 }
00233 
00234 
00238 static int
00239 init_lustre_counters( void  )
00240 {
00241         char lustre_dir[PATH_MAX];
00242     char path[PATH_MAX];
00243     char path_readahead[PATH_MAX],path_stats[PATH_MAX];
00244     char *ptr;
00245     char fs_name[100];
00246     int idx = 0;
00247     int tmp_fd;
00248     DIR *proc_dir;
00249     struct dirent *entry;
00250 
00251     sprintf(lustre_dir,"%s/llite",proc_base_path);
00252 
00253     proc_dir = opendir( lustre_dir );
00254     if ( proc_dir == NULL ) {
00255        SUBDBG("Cannot open %s\n",lustre_dir);
00256        return PAPI_ESYS;
00257     }
00258 
00259     entry = readdir( proc_dir );
00260 
00261     while ( entry != NULL ) {
00262        memset( path, 0, PATH_MAX );
00263        snprintf( path, PATH_MAX - 1, "%s/%s/stats", lustre_dir,
00264                   entry->d_name );
00265        SUBDBG("checking for file %s\n", path);
00266 
00267        if ( ( tmp_fd = open( path, O_RDONLY ) ) != -1 ) {
00268           close( tmp_fd );
00269 
00270           /* erase \r and \n at the end of path */
00271           /* why is this necessary?             */
00272 
00273           idx = strlen( path );
00274           idx--;
00275 
00276           while ( path[idx] == '\r' || path[idx] == '\n' )
00277             path[idx--] = 0;
00278 
00279           /* Lustre paths are of type server-UUID */
00280 
00281           idx = 0;
00282 
00283           ptr = strstr(path,"llite/") + 6;
00284 
00285           while ( *ptr && idx < 100 ) {
00286              fs_name[idx] = *ptr;
00287          ptr++;
00288          idx++;
00289           }
00290 
00291           SUBDBG("found Lustre FS: %s\n", fs_name);
00292 
00293           snprintf( path_stats, PATH_MAX - 1, 
00294             "%s/%s/stats", 
00295             lustre_dir,
00296             entry->d_name );
00297           SUBDBG("Found file %s\n", path_stats);
00298 
00299           snprintf( path_readahead, PATH_MAX - 1, 
00300             "%s/%s/read_ahead_stats", 
00301             lustre_dir,
00302             entry->d_name );
00303           SUBDBG("Now checking for file %s\n", path_readahead);
00304 
00305 
00306           strcpy( ptr, "read_ahead_stats" );
00307           addLustreFS( fs_name, path_stats, path_readahead );
00308 
00309        }
00310        entry = readdir( proc_dir );
00311     }
00312     closedir( proc_dir );
00313 
00314     return PAPI_OK;
00315 
00316 }
00317 
00321 static void
00322 read_lustre_counter( )
00323 {
00324     lustre_fs *fs = root_lustre_fs;
00325     FILE *fff;
00326     char buffer[BUFSIZ];
00327 
00328     while ( fs != NULL ) {
00329 
00330       /* read values from stats file */
00331       fff=fopen(fs->proc_file,"r" );
00332       if (fff != NULL) {
00333           while(1) {
00334             if (fgets(buffer,BUFSIZ,fff)==NULL) break;
00335     
00336             if (strstr( buffer, "write_bytes" )) {
00337               sscanf(buffer,"%*s %*d %*s %*s %*d %*d %lld",&fs->write_cntr->value);
00338               SUBDBG("Read %lld write_bytes\n",fs->write_cntr->value);
00339             }
00340     
00341             if (strstr( buffer, "read_bytes" )) {
00342               sscanf(buffer,"%*s %*d %*s %*s %*d %*d %lld",&fs->read_cntr->value);
00343               SUBDBG("Read %lld read_bytes\n",fs->read_cntr->value);
00344             }
00345           }
00346           fclose(fff);
00347       }
00348 
00349       fff=fopen(fs->proc_file_readahead,"r");
00350       if (fff != NULL) {
00351           while(1) {
00352             if (fgets(buffer,BUFSIZ,fff)==NULL) break;
00353     
00354             if (strstr( buffer, "read but discarded")) {
00355                sscanf(buffer,"%*s %*s %*s %lld",&fs->readahead_cntr->value);
00356                SUBDBG("Read %lld discared\n",fs->readahead_cntr->value);
00357                break;
00358             }
00359           }
00360           fclose(fff);
00361       }
00362       fs = fs->next;
00363     }
00364 }
00365 
00366 
00370 static void
00371 host_finalize( void )
00372 {
00373         int i;
00374     lustre_fs *fs, *next_fs;
00375     counter_info *cntr;
00376 
00377     for(i=0;i<num_events;i++) {
00378        cntr=lustre_native_table[i];
00379        if ( cntr != NULL ) {
00380           free( cntr->name );
00381           free( cntr->description );
00382           free( cntr->unit );
00383           free( cntr );       
00384        }
00385        lustre_native_table[i]=NULL;
00386     }
00387 
00388     fs = root_lustre_fs;
00389 
00390     while ( fs != NULL ) {
00391         next_fs = fs->next;
00392         free(fs->proc_file);
00393         free(fs->proc_file_readahead);
00394         free( fs );
00395         fs = next_fs;
00396     }
00397 
00398     root_lustre_fs = NULL;
00399 }
00400 
00401 
00405 static int
00406 detect_lustre()
00407 {
00408         char lustre_directory[BUFSIZ];
00409     DIR *proc_dir;
00410 
00411     sprintf(lustre_directory,"%s/llite",proc_base_path);
00412 
00413     proc_dir = opendir( proc_base_path );
00414     if ( proc_dir == NULL ) {
00415       SUBDBG("we are not able to read %s\n",lustre_directory);
00416        return PAPI_ESYS;
00417     }
00418 
00419     closedir(proc_dir);
00420 
00421     return PAPI_OK;
00422 }
00423 
00424 
00425 /*****************************************************************************
00426  *******************  BEGIN PAPI's COMPONENT REQUIRED FUNCTIONS  *************
00427  *****************************************************************************/
00428 
00429 /*
00430  * Component setup and shutdown
00431  */
00432 
00433 int
00434 _lustre_init_component( int cidx )
00435 {
00436 
00437     int ret = PAPI_OK;
00438 
00439     /* See if lustre filesystem exists */
00440     ret=detect_lustre();
00441     if (ret!=PAPI_OK) {
00442        strncpy(_lustre_vector.cmp_info.disabled_reason,
00443            "No lustre filesystems found",PAPI_MAX_STR_LEN);
00444        return ret;
00445     }
00446 
00447     resize_native_table();
00448     ret=init_lustre_counters();
00449 
00450     _lustre_vector.cmp_info.num_native_events=num_events;
00451     _lustre_vector.cmp_info.CmpIdx = cidx;
00452 
00453     return ret;
00454 }
00455 
00456 
00457 
00458 
00459 
00460 /*
00461  * This is called whenever a thread is initialized
00462  */
00463 int
00464 _lustre_init_thread( hwd_context_t * ctx )
00465 {
00466   (void) ctx;
00467 
00468   return PAPI_OK;
00469 }
00470 
00471 
00472 /*
00473  *
00474  */
00475 int
00476 _lustre_shutdown_component( void )
00477 {
00478 
00479     host_finalize(  );
00480     papi_free( lustre_native_table );
00481 
00482     return PAPI_OK;
00483 }
00484 
00485 /*
00486  *
00487  */
00488 int
00489 _lustre_shutdown_thread( hwd_context_t * ctx )
00490 {
00491     ( void ) ctx;
00492 
00493     return PAPI_OK;
00494 }
00495 
00496 
00497 
00498 /*
00499  * Control of counters (Reading/Writing/Starting/Stopping/Setup) functions
00500  */
00501 int
00502 _lustre_init_control_state( hwd_control_state_t *ctl )
00503 {
00504     LUSTRE_control_state_t *lustre_ctl = (LUSTRE_control_state_t *)ctl;
00505 
00506     memset(lustre_ctl->start_count,0,sizeof(long long)*LUSTRE_MAX_COUNTERS);
00507     memset(lustre_ctl->current_count,0,sizeof(long long)*LUSTRE_MAX_COUNTERS);
00508 
00509     return PAPI_OK;
00510 }
00511 
00512 
00513 /*
00514  *
00515  */
00516 int
00517 _lustre_update_control_state( hwd_control_state_t *ctl, 
00518                   NativeInfo_t *native,
00519                   int count, 
00520                   hwd_context_t *ctx )
00521 {
00522     LUSTRE_control_state_t *lustre_ctl = (LUSTRE_control_state_t *)ctl;
00523     ( void ) ctx;
00524     int i, index;
00525 
00526     for ( i = 0; i < count; i++ ) {
00527        index = native[i].ni_event;
00528        lustre_ctl->which_counter[i]=index;
00529        native[i].ni_position = i;
00530     }
00531 
00532     lustre_ctl->num_events=count;
00533 
00534     return PAPI_OK;
00535 }
00536 
00537 
00538 /*
00539  *
00540  */
00541 int
00542 _lustre_start( hwd_context_t *ctx, hwd_control_state_t *ctl )
00543 {
00544     ( void ) ctx;
00545 
00546     LUSTRE_control_state_t *lustre_ctl = (LUSTRE_control_state_t *)ctl;
00547     int i;
00548 
00549     read_lustre_counter(  );
00550 
00551     for(i=0;i<lustre_ctl->num_events;i++) {
00552        lustre_ctl->current_count[i]=
00553                  lustre_native_table[lustre_ctl->which_counter[i]]->value;
00554     }
00555 
00556     memcpy( lustre_ctl->start_count,
00557         lustre_ctl->current_count,
00558         LUSTRE_MAX_COUNTERS * sizeof ( long long ) );
00559 
00560     return PAPI_OK;
00561 }
00562 
00563 
00564 /*
00565  *
00566  */
00567 int
00568 _lustre_stop( hwd_context_t *ctx, hwd_control_state_t *ctl )
00569 {
00570 
00571     (void) ctx;
00572     LUSTRE_control_state_t *lustre_ctl = (LUSTRE_control_state_t *)ctl;
00573     int i;
00574 
00575     read_lustre_counter(  );
00576 
00577     for(i=0;i<lustre_ctl->num_events;i++) {
00578        lustre_ctl->current_count[i]=
00579                  lustre_native_table[lustre_ctl->which_counter[i]]->value;
00580     }
00581 
00582     return PAPI_OK;
00583 
00584 }
00585 
00586 
00587 
00588 /*
00589  *
00590  */
00591 int
00592 _lustre_read( hwd_context_t *ctx, hwd_control_state_t *ctl,
00593              long long **events, int flags )
00594 {
00595     (void) ctx;
00596     ( void ) flags;
00597 
00598     LUSTRE_control_state_t *lustre_ctl = (LUSTRE_control_state_t *)ctl;
00599     int i;
00600 
00601     read_lustre_counter(  );
00602 
00603     for(i=0;i<lustre_ctl->num_events;i++) {
00604        lustre_ctl->current_count[i]=
00605                  lustre_native_table[lustre_ctl->which_counter[i]]->value;
00606        lustre_ctl->difference[i]=lustre_ctl->current_count[i]-
00607                                          lustre_ctl->start_count[i];
00608     }
00609 
00610     *events = lustre_ctl->difference;
00611 
00612     return PAPI_OK;
00613 
00614 }
00615 
00616 
00617 
00618 
00619 /*
00620  *
00621  */
00622 int
00623 _lustre_reset( hwd_context_t * ctx, hwd_control_state_t * ctrl )
00624 {
00625 
00626   /* re-initializes counter_start values to current */
00627 
00628   _lustre_start(ctx,ctrl);
00629 
00630   return PAPI_OK;
00631 }
00632 
00633 
00634 /*
00635  *
00636  */
00637 int
00638 _lustre_write( hwd_context_t * ctx, hwd_control_state_t * ctrl, long long *from )
00639 {
00640     ( void ) ctx;
00641     ( void ) ctrl;
00642     ( void ) from;
00643 
00644     return PAPI_OK;
00645 }
00646 
00647 
00648 /*
00649  * Functions for setting up various options
00650  */
00651 
00652 /* This function sets various options in the component
00653  * The valid codes being passed in are PAPI_SET_DEFDOM,
00654  * PAPI_SET_DOMAIN, PAPI_SETDEFGRN, PAPI_SET_GRANUL * and PAPI_SET_INHERIT
00655  */
00656 int
00657 _lustre_ctl( hwd_context_t * ctx, int code, _papi_int_option_t * option )
00658 {
00659     ( void ) ctx;
00660     ( void ) code;
00661     ( void ) option;
00662 
00663     return PAPI_OK;
00664 }
00665 
00666 
00667 /*
00668  * This function has to set the bits needed to count different domains
00669  * In particular: PAPI_DOM_USER, PAPI_DOM_KERNEL PAPI_DOM_OTHER
00670  * By default return PAPI_EINVAL if none of those are specified
00671  * and PAPI_OK with success
00672  * PAPI_DOM_USER is only user context is counted
00673  * PAPI_DOM_KERNEL is only the Kernel/OS context is counted
00674  * PAPI_DOM_OTHER  is Exception/transient mode (like user TLB misses)
00675  * PAPI_DOM_ALL   is all of the domains
00676  */
00677 int
00678 _lustre_set_domain( hwd_control_state_t * cntrl, int domain )
00679 {
00680     ( void ) cntrl;
00681     int found = 0;
00682     if ( PAPI_DOM_USER & domain ) {
00683         found = 1;
00684     }
00685     if ( PAPI_DOM_KERNEL & domain ) {
00686         found = 1;
00687     }
00688     if ( PAPI_DOM_OTHER & domain ) {
00689         found = 1;
00690     }
00691     if ( !found )
00692         return PAPI_EINVAL;
00693 
00694     return PAPI_OK;
00695 }
00696 
00697 
00698 /*
00699  *
00700  */
00701 int
00702 _lustre_ntv_code_to_name( unsigned int EventCode, char *name, int len )
00703 {
00704 
00705   int event=EventCode;
00706 
00707   if (event >=0 && event < num_events) {
00708      strncpy( name, lustre_native_table[event]->name, len );
00709      return PAPI_OK;
00710   }
00711   return PAPI_ENOEVNT;
00712 }
00713 
00714 
00715 /*
00716  *
00717  */
00718 int
00719 _lustre_ntv_code_to_descr( unsigned int EventCode, char *name, int len )
00720 {
00721 
00722   int event=EventCode;
00723 
00724   if (event >=0 && event < num_events) {
00725     strncpy( name, lustre_native_table[event]->description, len );
00726     return PAPI_OK;
00727   }
00728   return PAPI_ENOEVNT;
00729 }
00730 
00731 
00732 /*
00733  *
00734  */
00735 int
00736 _lustre_ntv_enum_events( unsigned int *EventCode, int modifier )
00737 {
00738 
00739     if ( modifier == PAPI_ENUM_FIRST ) {
00740        if (num_events==0) return PAPI_ENOEVNT;
00741        *EventCode = 0;
00742        return PAPI_OK;
00743     }
00744 
00745     if ( modifier == PAPI_ENUM_EVENTS ) {
00746         int index = *EventCode;
00747 
00748         if ( lustre_native_table[index + 1] ) {
00749             *EventCode = *EventCode + 1;
00750             return PAPI_OK;
00751         } else {
00752             return PAPI_ENOEVNT;
00753         }
00754     } 
00755         
00756 
00757     return PAPI_EINVAL;
00758 }
00759 
00760 
00761 /*
00762  *
00763  */
00764 papi_vector_t _lustre_vector = {
00765    .cmp_info = {
00766         /* component information (unspecified values initialized to 0) */
00767        .name = "lustre",
00768        .short_name = "lustre",
00769        .version = "1.9",
00770        .description = "Lustre filesystem statistics",
00771        .num_mpx_cntrs = LUSTRE_MAX_COUNTERS,
00772        .num_cntrs = LUSTRE_MAX_COUNTERS,
00773        .default_domain = PAPI_DOM_USER,
00774        .default_granularity = PAPI_GRN_THR,
00775        .available_granularities = PAPI_GRN_THR,
00776        .hardware_intr_sig = PAPI_INT_SIGNAL,
00777 
00778        /* component specific cmp_info initializations */
00779        .fast_real_timer = 0,
00780        .fast_virtual_timer = 0,
00781        .attach = 0,
00782        .attach_must_ptrace = 0,
00783        .available_domains = PAPI_DOM_USER | PAPI_DOM_KERNEL,
00784   },
00785 
00786      /* sizes of framework-opaque component-private structures */
00787   .size = {
00788        .context = sizeof ( LUSTRE_context_t ),
00789        .control_state = sizeof ( LUSTRE_control_state_t ),
00790        .reg_value = sizeof ( LUSTRE_register_t ),
00791        .reg_alloc = sizeof ( LUSTRE_reg_alloc_t ),
00792   },
00793 
00794      /* function pointers in this component */
00795   .init_thread =           _lustre_init_thread,
00796   .init_component =        _lustre_init_component,
00797   .init_control_state =    _lustre_init_control_state,
00798   .start =                 _lustre_start,
00799   .stop =                  _lustre_stop,
00800   .read =                  _lustre_read,
00801   .shutdown_thread =       _lustre_shutdown_thread,
00802   .shutdown_component =    _lustre_shutdown_component,
00803   .ctl =                   _lustre_ctl,
00804   .update_control_state =  _lustre_update_control_state,
00805   .set_domain =            _lustre_set_domain,
00806   .reset =                 _lustre_reset,
00807 
00808   .ntv_enum_events =   _lustre_ntv_enum_events,
00809   .ntv_code_to_name =  _lustre_ntv_code_to_name,
00810   .ntv_code_to_descr = _lustre_ntv_code_to_descr,
00811 
00812 };
00813 
00814 
00815 
00816 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines