LCOV - code coverage report
Current view: top level - disco/diag - fd_proc_interrupts.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 243 0.0 %
Date: 2026-06-29 05:51:35 Functions: 0 9 0.0 %

          Line data    Source code
       1             : #include "fd_proc_interrupts.h"
       2             : #include "../../util/tile/fd_tile.h" /* FD_TILE_MAX */
       3             : #include "../../util/io/fd_io.h" /* fd_io_buffered_istream */
       4             : #include <ctype.h> /* isdigit */
       5             : 
       6             : static void
       7           0 : skip_spaces( fd_io_buffered_istream_t * is ) {
       8           0 :   char const * peek    = fd_io_buffered_istream_peek   ( is );
       9           0 :   ulong        peek_sz = fd_io_buffered_istream_peek_sz( is );
      10           0 :   ulong j;
      11           0 :   for( j=0UL; j<peek_sz && peek[j]==' '; j++ ) {}
      12           0 :   fd_io_buffered_istream_skip( is, j );
      13           0 : }
      14             : 
      15             : static void
      16           0 : skip_token( fd_io_buffered_istream_t * is ) {
      17           0 :   char const * peek    = fd_io_buffered_istream_peek   ( is );
      18           0 :   ulong        peek_sz = fd_io_buffered_istream_peek_sz( is );
      19           0 :   ulong j;
      20           0 :   for( j=0UL; j<peek_sz && peek[j]!=' ' && peek[j]!='\n'; j++ ) {}
      21           0 :   fd_io_buffered_istream_skip( is, j );
      22           0 : }
      23             : 
      24             : static void
      25           0 : skip_line( fd_io_buffered_istream_t * is ) {
      26           0 :   char const * peek    = fd_io_buffered_istream_peek   ( is );
      27           0 :   ulong        peek_sz = fd_io_buffered_istream_peek_sz( is );
      28           0 :   ulong j;
      29           0 :   for( j=0UL; j<peek_sz && peek[j]!='\n'; j++ ) {}
      30           0 :   if( j<peek_sz && peek[j]=='\n' ) j++;
      31           0 :   fd_io_buffered_istream_skip( is, j );
      32           0 : }
      33             : 
      34             : /* read_ulong consumes a decimal ulong from buffered unconsumed chars in
      35             :    is.  Returns ULONG_MAX if parse failed. */
      36             : 
      37             : static ulong
      38           0 : read_ulong( fd_io_buffered_istream_t * is ) {
      39           0 :   char const * peek    = fd_io_buffered_istream_peek   ( is );
      40           0 :   ulong        peek_sz = fd_io_buffered_istream_peek_sz( is );
      41           0 :   char num[ 21 ];
      42           0 :   peek_sz = fd_ulong_min( peek_sz, 20 );
      43           0 :   ulong num_sz;
      44           0 :   for( num_sz=0UL; num_sz<peek_sz && isdigit( peek[num_sz] ); num_sz++ ) {}
      45           0 :   memcpy( num, peek, num_sz );
      46           0 :   num[ num_sz ] = '\0';
      47           0 :   fd_io_buffered_istream_skip( is, num_sz );
      48           0 :   if( FD_UNLIKELY( num_sz==0 ) ) return ULONG_MAX;
      49           0 :   return fd_cstr_to_ulong( num );
      50           0 : }
      51             : 
      52             : static int
      53             : read_until( fd_io_buffered_istream_t * is,
      54             :             ulong                      min_sz,
      55           0 :             void (*skip)( fd_io_buffered_istream_t * is ) ) {
      56             : 
      57           0 :   ulong buf_sz = fd_io_buffered_istream_rbuf_sz( is );
      58           0 :   min_sz = fd_ulong_min( min_sz, buf_sz );
      59             : 
      60             :   /* Read until 'skip' leaves some bytes */
      61             : 
      62           0 :   for(;;) {
      63           0 :     skip( is );
      64           0 :     if( fd_io_buffered_istream_peek_sz( is )>0 ) break;
      65           0 :     int err = fd_io_buffered_istream_fetch( is );
      66           0 :     if( err==0 ) {
      67           0 :       continue;
      68           0 :     }
      69           0 :     if( err==-1 ) {
      70           0 :       if( fd_io_buffered_istream_peek_sz( is )==0 ) return -1;
      71           0 :       break;
      72           0 :     }
      73           0 :     return err;
      74           0 :   }
      75             : 
      76             :   /* Read ahead */
      77             : 
      78           0 :   while( fd_io_buffered_istream_peek_sz( is )<min_sz ) {
      79           0 :     int err = fd_io_buffered_istream_fetch( is );
      80           0 :     if( err==-1 ) break;
      81           0 :     if( err!=0  ) return err;
      82           0 :   }
      83             : 
      84           0 :   return 0;
      85           0 : }
      86             : 
      87             : /* read_cpu_map reads the first line of /proc/interrupts mapping columns
      88             :    to CPUs.  Usually 0,1,2,3,... but has gaps for offline CPUs.  Also
      89             :    used for /proc/softirqs.  Formatted like this:
      90             :    "   CPU0  CPU1  CPU2  CPU3\n" */
      91             : 
      92             : static int
      93             : read_cpu_map(  fd_io_buffered_istream_t * is,
      94             :                ulong *                    out_col_cnt,
      95             :                ulong *                    out_cpu_cnt,
      96           0 :                ushort                     col_cpu[ FD_TILE_MAX ] ) {
      97           0 :   *out_col_cnt = 0UL;
      98           0 :   *out_cpu_cnt = 0UL;
      99             : 
     100             :   /* Read first line */
     101           0 :   ulong col_cnt = 0UL;
     102           0 :   do {
     103           0 :     int err = read_until( is, 16UL, skip_spaces );
     104           0 :     if( FD_UNLIKELY( err!=0 ) ) return err;
     105           0 :     char const * peek    = fd_io_buffered_istream_peek   ( is );
     106           0 :     ulong        peek_sz = fd_io_buffered_istream_peek_sz( is );
     107           0 :     if( peek[0]=='\n' ) break;
     108           0 :     if( peek_sz<4     ) break;
     109             : 
     110             :     /* Filter for 'CPU<num>' column */
     111           0 :     if( 0!=memcmp( peek, "CPU", 3 ) ) break;
     112           0 :     fd_io_buffered_istream_skip( is, 3 );
     113           0 :     peek    = fd_io_buffered_istream_peek   ( is );
     114           0 :     peek_sz = fd_io_buffered_istream_peek_sz( is );
     115             : 
     116             :     /* Parse number */
     117           0 :     ulong cpu_idx = read_ulong( is );
     118           0 :     if( FD_UNLIKELY( cpu_idx==ULONG_MAX ) ) {
     119           0 :       FD_LOG_WARNING(( "Failed to parse first line of /proc/interrupts" ));
     120           0 :       break;
     121           0 :     }
     122           0 :     if( FD_UNLIKELY( cpu_idx>=FD_TILE_MAX ) ) {
     123           0 :       FD_LOG_WARNING(( "Out of bounds: CPU%lu", cpu_idx ));
     124           0 :       break;
     125           0 :     }
     126             : 
     127           0 :     col_cpu[ col_cnt++ ] = (ushort)cpu_idx;
     128           0 :   } while( col_cnt<FD_TILE_MAX );
     129             : 
     130             :   /* Skip rest of line */
     131           0 :   int err = read_until( is, 0UL, skip_line );
     132           0 :   if( FD_UNLIKELY( err!=0 ) ) return err;
     133             : 
     134             :   /* Verify CPU map */
     135           0 :   if( FD_UNLIKELY( col_cnt==0UL ) ) {
     136           0 :     FD_LOG_WARNING(( "No CPUs found reading /proc/interrupts" ));
     137           0 :     return 0;
     138           0 :   }
     139           0 :   ulong cpu_cnt = 0UL;
     140           0 :   for( ulong col_idx=0UL; col_idx<col_cnt; col_idx++ ) {
     141           0 :     ulong next_cpu_cnt = col_cpu[ col_idx ]+1UL;
     142           0 :     if( FD_UNLIKELY( next_cpu_cnt<=cpu_cnt ) ) {
     143           0 :       FD_LOG_WARNING(( "CPU%u out of order reading /proc/interrupts", col_cpu[ col_idx ] ));
     144           0 :       return 0;
     145           0 :     }
     146           0 :     cpu_cnt = next_cpu_cnt;
     147           0 :   }
     148           0 :   if( FD_UNLIKELY( cpu_cnt>FD_TILE_MAX ) ) {
     149           0 :     FD_LOG_WARNING(( "Too many CPUs found reading /proc/interrupts" ));
     150           0 :     return 0;
     151           0 :   }
     152             : 
     153           0 :   *out_cpu_cnt = cpu_cnt;
     154           0 :   *out_col_cnt = col_cnt;
     155           0 :   return 0;
     156           0 : }
     157             : 
     158             : ulong
     159             : fd_proc_interrupts_colwise( int   fd,
     160           0 :                             ulong per_cpu[ FD_TILE_MAX ] ) {
     161           0 :   fd_io_buffered_istream_t is[1];
     162           0 :   char buf[ 4096 ];
     163           0 :   fd_io_buffered_istream_init( is, fd, buf, sizeof(buf) );
     164             : 
     165             :   /* Read first line */
     166             : 
     167           0 :   ushort col_cpu[ FD_TILE_MAX ];
     168           0 :   ulong  col_cnt;
     169           0 :   ulong  cpu_cnt;
     170           0 :   int err = read_cpu_map( is, &col_cnt, &cpu_cnt, col_cpu );
     171           0 :   if( FD_UNLIKELY( err!=0 ) ) goto failed;
     172           0 :   if( FD_UNLIKELY( !col_cnt || !cpu_cnt ) ) return 0UL;
     173             : 
     174           0 :   for( ulong cpu=0UL; cpu<cpu_cnt; cpu++ ) {
     175           0 :     per_cpu[ cpu ] = 0UL;
     176           0 :   }
     177             : 
     178             :   /* Read interrupt table
     179             :      Device interrupt counters look like this:
     180             :      "  123:  41  42  43  44"
     181             :      Special interrupts look like this:
     182             :      "  NMI:   1   2   3   4" */
     183             : 
     184           0 :   for(;;) { /* each line */
     185             : 
     186             :     /* Read prefix */
     187           0 :     err = read_until( is, 64UL, skip_spaces );
     188           0 :     if( FD_UNLIKELY( err!=0 ) ) goto failed;
     189           0 :     if( fd_io_buffered_istream_peek_sz( is )==0 ) return cpu_cnt;
     190           0 :     if( !isdigit( ((char const *)fd_io_buffered_istream_peek( is ))[0] ) ) {
     191             :       /* Only count numbered interrupts */
     192           0 :       goto skip_line;
     193           0 :     }
     194           0 :     err = read_until( is, 0UL, skip_token );
     195           0 :     if( FD_UNLIKELY( err!=0 ) ) goto failed;
     196             : 
     197             :     /* Read interrupt counters */
     198           0 :     for( ulong col_idx=0UL; col_idx<col_cnt; col_idx++ ) {
     199           0 :       err = read_until( is, 21UL, skip_spaces );
     200           0 :       if( FD_UNLIKELY( err!=0 ) ) goto failed;
     201             : 
     202           0 :       ulong irq_cnt = read_ulong( is );
     203           0 :       irq_cnt = fd_ulong_if( irq_cnt!=ULONG_MAX, irq_cnt, 0UL );
     204           0 :       per_cpu[ col_cpu[ col_idx ] ] += irq_cnt;
     205           0 :     }
     206             : 
     207           0 :   skip_line:
     208             :     /* Ignore rest of line */
     209           0 :     err = read_until( is, 0UL, skip_line );
     210           0 :     if( FD_UNLIKELY( err!=0 ) ) {
     211           0 :       if( err==-1 ) break;
     212           0 :       goto failed;
     213           0 :     }
     214             : 
     215           0 :   }
     216           0 :   return cpu_cnt;
     217             : 
     218           0 : failed:
     219           0 :   if( err!=0 ) {
     220           0 :     FD_LOG_WARNING(( "read failed (%i-%s)", err, fd_io_strerror( err ) ));
     221           0 :   }
     222           0 :   return 0UL;
     223           0 : }
     224             : 
     225             : ulong
     226             : fd_proc_interrupts_tlb( int   fd,
     227           0 :                         ulong per_cpu[ FD_TILE_MAX ] ) {
     228           0 :   fd_io_buffered_istream_t is[1];
     229           0 :   char buf[ 4096 ];
     230           0 :   fd_io_buffered_istream_init( is, fd, buf, sizeof(buf) );
     231             : 
     232           0 :   ushort col_cpu[ FD_TILE_MAX ];
     233           0 :   ulong  col_cnt;
     234           0 :   ulong  cpu_cnt;
     235           0 :   int err = read_cpu_map( is, &col_cnt, &cpu_cnt, col_cpu );
     236           0 :   if( FD_UNLIKELY( err!=0 ) ) goto failed;
     237           0 :   if( FD_UNLIKELY( !col_cnt || !cpu_cnt ) ) return 0UL;
     238             : 
     239           0 :   for( ulong cpu=0UL; cpu<cpu_cnt; cpu++ ) {
     240           0 :     per_cpu[ cpu ] = 0UL;
     241           0 :   }
     242             : 
     243           0 :   for(;;) {
     244           0 :     err = read_until( is, 64UL, skip_spaces );
     245           0 :     if( FD_UNLIKELY( err!=0 ) ) goto failed;
     246           0 :     if( fd_io_buffered_istream_peek_sz( is )==0 ) return cpu_cnt;
     247             : 
     248           0 :     char const * prefix     = fd_io_buffered_istream_peek   ( is );
     249           0 :     ulong        prefix_max = fd_io_buffered_istream_peek_sz( is );
     250           0 :     if( FD_UNLIKELY( prefix_max>=4UL && fd_memeq( prefix, "TLB:", 4UL ) ) ) {
     251           0 :       err = read_until( is, 0UL, skip_token );
     252           0 :       if( FD_UNLIKELY( err!=0 ) ) goto failed;
     253             : 
     254           0 :       for( ulong col_idx=0UL; col_idx<col_cnt; col_idx++ ) {
     255           0 :         err = read_until( is, 21UL, skip_spaces );
     256           0 :         if( FD_UNLIKELY( err!=0 ) ) goto failed;
     257             : 
     258           0 :         ulong irq_cnt = read_ulong( is );
     259           0 :         irq_cnt = fd_ulong_if( irq_cnt!=ULONG_MAX, irq_cnt, 0UL );
     260           0 :         per_cpu[ col_cpu[ col_idx ] ] = irq_cnt;
     261           0 :       }
     262           0 :       return cpu_cnt;
     263           0 :     }
     264             : 
     265           0 :     err = read_until( is, 0UL, skip_line );
     266           0 :     if( FD_UNLIKELY( err!=0 ) ) {
     267           0 :       if( err==-1 ) break;
     268           0 :       goto failed;
     269           0 :     }
     270           0 :   }
     271           0 :   return cpu_cnt;
     272             : 
     273           0 : failed:
     274           0 :   if( err!=0 ) {
     275           0 :     FD_LOG_WARNING(( "read failed (%i-%s)", err, fd_io_strerror( err ) ));
     276           0 :   }
     277           0 :   return 0UL;
     278           0 : }
     279             : 
     280             : ulong
     281             : fd_proc_softirqs_sum( int   fd,
     282           0 :                       ulong per_cpu[ FD_METRICS_ENUM_SOFTIRQ_CNT ][ FD_TILE_MAX ] ) {
     283           0 :   fd_io_buffered_istream_t is[1];
     284           0 :   char buf[ 4096 ];
     285           0 :   fd_io_buffered_istream_init( is, fd, buf, sizeof(buf) );
     286             : 
     287             :   /* Read first line */
     288             : 
     289           0 :   ushort col_cpu[ FD_TILE_MAX ];
     290           0 :   ulong  col_cnt;
     291           0 :   ulong  cpu_cnt;
     292           0 :   int err = read_cpu_map( is, &col_cnt, &cpu_cnt, col_cpu );
     293           0 :   if( FD_UNLIKELY( err!=0 ) ) goto failed;
     294           0 :   if( FD_UNLIKELY( !col_cnt || !cpu_cnt ) ) return 0UL;
     295           0 :   for( ulong i=0UL; i<FD_METRICS_ENUM_SOFTIRQ_CNT; i++ ) {
     296           0 :     for( ulong c=0UL; c<cpu_cnt; c++ ) per_cpu[ i ][ c ] = 0UL;
     297           0 :   }
     298             : 
     299             :   /* Read softirq table
     300             :      Looks like this:
     301             :      "   NET_TX:   1   2   3   5" */
     302             : 
     303           0 :   for(;;) { /* each line */
     304             : 
     305             :     /* Read prefix */
     306           0 :     err = read_until( is, 64UL, skip_spaces );
     307           0 :     if( FD_UNLIKELY( err!=0 ) ) goto failed;
     308           0 :     if( fd_io_buffered_istream_peek_sz( is )==0 ) return cpu_cnt;
     309             : 
     310             :     /* Match prefix */
     311           0 :     int          kind       = FD_METRICS_ENUM_SOFTIRQ_V_OTHER_IDX;
     312           0 :     char const * prefix     = fd_io_buffered_istream_peek   ( is );
     313           0 :     ulong        prefix_max = fd_io_buffered_istream_peek_sz( is );
     314           0 :     if( prefix_max>=7 && fd_memeq( prefix, "NET_TX:", 7 ) ) {
     315           0 :       kind = FD_METRICS_ENUM_SOFTIRQ_V_NET_IDX;
     316           0 :     } else if( prefix_max>=7 && fd_memeq( prefix, "NET_RX:", 7 ) ) {
     317           0 :       kind = FD_METRICS_ENUM_SOFTIRQ_V_NET_IDX;
     318           0 :     } else if( prefix_max>=6 && fd_memeq( prefix, "BLOCK:", 6 ) ) {
     319           0 :       kind = FD_METRICS_ENUM_SOFTIRQ_V_DISK_IDX;
     320           0 :     }
     321           0 :     err = read_until( is, 0UL, skip_token );
     322           0 :     if( FD_UNLIKELY( err!=0 ) ) goto failed;
     323             : 
     324             :     /* Read interrupt counters */
     325           0 :     for( ulong col_idx=0UL; col_idx<col_cnt; col_idx++ ) {
     326           0 :       err = read_until( is, 21UL, skip_spaces );
     327           0 :       if( FD_UNLIKELY( err!=0 ) ) goto failed;
     328             : 
     329           0 :       ulong irq_cnt = read_ulong( is );
     330           0 :       irq_cnt = fd_ulong_if( irq_cnt!=ULONG_MAX, irq_cnt, 0UL );
     331           0 :       per_cpu[ kind ][ col_cpu[ col_idx ] ] += irq_cnt;
     332           0 :     }
     333             : 
     334             :     /* Ignore rest of line */
     335           0 :     err = read_until( is, 0UL, skip_line );
     336           0 :     if( FD_UNLIKELY( err!=0 ) ) {
     337           0 :       if( err==-1 ) break;
     338           0 :       goto failed;
     339           0 :     }
     340             : 
     341           0 :   }
     342           0 :   return cpu_cnt;
     343             : 
     344           0 : failed:
     345           0 :   if( err!=0 ) {
     346           0 :     FD_LOG_WARNING(( "read failed (%i-%s)", err, fd_io_strerror( err ) ));
     347           0 :   }
     348           0 :   return 0UL;
     349           0 : }

Generated by: LCOV version 1.14