LCOV - code coverage report
Current view: top level - disco/diag - fd_proc_interrupts.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 308 0.0 %
Date: 2026-08-13 04:56:22 Functions: 0 12 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             : /* The skip_* helpers consume a run of bytes from is.  Each returns 1 if
       7             :    it stopped at a genuine terminator and 0 if it consumed every
       8             :    buffered byte without reaching a terminator. */
       9             : 
      10             : static int
      11           0 : skip_spaces( fd_io_buffered_istream_t * is ) {
      12           0 :   char const * peek    = fd_io_buffered_istream_peek   ( is );
      13           0 :   ulong        peek_sz = fd_io_buffered_istream_peek_sz( is );
      14           0 :   ulong j;
      15           0 :   for( j=0UL; j<peek_sz && peek[j]==' '; j++ ) {}
      16           0 :   fd_io_buffered_istream_skip( is, j );
      17           0 :   return j<peek_sz; /* complete iff we stopped on a non-space */
      18           0 : }
      19             : 
      20             : static int
      21           0 : skip_token( fd_io_buffered_istream_t * is ) {
      22           0 :   char const * peek    = fd_io_buffered_istream_peek   ( is );
      23           0 :   ulong        peek_sz = fd_io_buffered_istream_peek_sz( is );
      24           0 :   ulong j;
      25           0 :   for( j=0UL; j<peek_sz && peek[j]!=' ' && peek[j]!='\n'; j++ ) {}
      26           0 :   fd_io_buffered_istream_skip( is, j );
      27           0 :   return j<peek_sz; /* complete iff we stopped on a delimiter */
      28           0 : }
      29             : 
      30             : static int
      31           0 : skip_line( fd_io_buffered_istream_t * is ) {
      32           0 :   char const * peek    = fd_io_buffered_istream_peek   ( is );
      33           0 :   ulong        peek_sz = fd_io_buffered_istream_peek_sz( is );
      34           0 :   ulong j;
      35           0 :   for( j=0UL; j<peek_sz && peek[j]!='\n'; j++ ) {}
      36           0 :   int complete = j<peek_sz; /* found the '\n' */
      37           0 :   if( complete ) j++;       /* consume the '\n' */
      38           0 :   fd_io_buffered_istream_skip( is, j );
      39           0 :   return complete;
      40           0 : }
      41             : 
      42             : /* read_ulong consumes a decimal ulong from buffered unconsumed chars in
      43             :    is.  Returns ULONG_MAX if parse failed. */
      44             : 
      45             : static ulong
      46           0 : read_ulong( fd_io_buffered_istream_t * is ) {
      47           0 :   char const * peek    = fd_io_buffered_istream_peek   ( is );
      48           0 :   ulong        peek_sz = fd_io_buffered_istream_peek_sz( is );
      49           0 :   char num[ 21 ];
      50           0 :   peek_sz = fd_ulong_min( peek_sz, 20 );
      51           0 :   ulong num_sz;
      52           0 :   for( num_sz=0UL; num_sz<peek_sz && isdigit( peek[num_sz] ); num_sz++ ) {}
      53           0 :   memcpy( num, peek, num_sz );
      54           0 :   num[ num_sz ] = '\0';
      55           0 :   fd_io_buffered_istream_skip( is, num_sz );
      56           0 :   if( FD_UNLIKELY( num_sz==0 ) ) return ULONG_MAX;
      57           0 :   return fd_cstr_to_ulong( num );
      58           0 : }
      59             : 
      60             : static int
      61             : read_until( fd_io_buffered_istream_t * is,
      62             :            ulong                      min_sz,
      63           0 :            int (*skip)( fd_io_buffered_istream_t * is ) ) {
      64             : 
      65           0 :   ulong buf_sz = fd_io_buffered_istream_rbuf_sz( is );
      66           0 :   min_sz = fd_ulong_min( min_sz, buf_sz );
      67             : 
      68             :   /* Read until 'skip' leaves some bytes */
      69             : 
      70           0 :   for(;;) {
      71           0 :     if( skip( is ) ) break; /* unit complete */
      72           0 :     int err = fd_io_buffered_istream_fetch( is );
      73           0 :     if( err==0 ) {
      74           0 :       continue;
      75           0 :     }
      76           0 :     if( err==-1 ) {
      77           0 :       if( fd_io_buffered_istream_peek_sz( is )==0 ) return -1;
      78           0 :       break;
      79           0 :     }
      80           0 :     return err;
      81           0 :   }
      82             : 
      83             :   /* Read ahead */
      84             : 
      85           0 :   while( fd_io_buffered_istream_peek_sz( is )<min_sz ) {
      86           0 :     int err = fd_io_buffered_istream_fetch( is );
      87           0 :     if( err==-1 ) break;
      88           0 :     if( err!=0  ) return err;
      89           0 :   }
      90             : 
      91           0 :   return 0;
      92           0 : }
      93             : 
      94             : /* read_cpu_map reads the first line of /proc/interrupts mapping columns
      95             :    to CPUs.  Usually 0,1,2,3,... but has gaps for offline CPUs.  Also
      96             :    used for /proc/softirqs.  Formatted like this:
      97             :    "   CPU0  CPU1  CPU2  CPU3\n" */
      98             : 
      99             : static int
     100             : read_cpu_map(  fd_io_buffered_istream_t * is,
     101             :                ulong *                    out_col_cnt,
     102             :                ulong *                    out_cpu_cnt,
     103           0 :                ushort                     col_cpu[ FD_TILE_MAX ] ) {
     104           0 :   *out_col_cnt = 0UL;
     105           0 :   *out_cpu_cnt = 0UL;
     106             : 
     107             :   /* Read first line */
     108           0 :   ulong col_cnt = 0UL;
     109           0 :   do {
     110           0 :     int err = read_until( is, 16UL, skip_spaces );
     111           0 :     if( FD_UNLIKELY( err!=0 ) ) return err;
     112           0 :     char const * peek    = fd_io_buffered_istream_peek   ( is );
     113           0 :     ulong        peek_sz = fd_io_buffered_istream_peek_sz( is );
     114           0 :     if( peek[0]=='\n' ) break;
     115           0 :     if( peek_sz<4     ) break;
     116             : 
     117             :     /* Filter for 'CPU<num>' column */
     118           0 :     if( 0!=memcmp( peek, "CPU", 3 ) ) break;
     119           0 :     fd_io_buffered_istream_skip( is, 3 );
     120           0 :     peek    = fd_io_buffered_istream_peek   ( is );
     121           0 :     peek_sz = fd_io_buffered_istream_peek_sz( is );
     122             : 
     123             :     /* Parse number */
     124           0 :     ulong cpu_idx = read_ulong( is );
     125           0 :     if( FD_UNLIKELY( cpu_idx==ULONG_MAX ) ) {
     126           0 :       FD_LOG_WARNING(( "Failed to parse first line of /proc/interrupts" ));
     127           0 :       break;
     128           0 :     }
     129           0 :     if( FD_UNLIKELY( cpu_idx>=FD_TILE_MAX ) ) {
     130           0 :       FD_LOG_WARNING(( "Out of bounds: CPU%lu", cpu_idx ));
     131           0 :       break;
     132           0 :     }
     133             : 
     134           0 :     col_cpu[ col_cnt++ ] = (ushort)cpu_idx;
     135           0 :   } while( col_cnt<FD_TILE_MAX );
     136             : 
     137             :   /* Skip rest of line */
     138           0 :   int err = read_until( is, 0UL, skip_line );
     139           0 :   if( FD_UNLIKELY( err!=0 ) ) return err;
     140             : 
     141             :   /* Verify CPU map */
     142           0 :   if( FD_UNLIKELY( col_cnt==0UL ) ) {
     143           0 :     FD_LOG_WARNING(( "No CPUs found reading /proc/interrupts" ));
     144           0 :     return 0;
     145           0 :   }
     146           0 :   ulong cpu_cnt = 0UL;
     147           0 :   for( ulong col_idx=0UL; col_idx<col_cnt; col_idx++ ) {
     148           0 :     ulong next_cpu_cnt = col_cpu[ col_idx ]+1UL;
     149           0 :     if( FD_UNLIKELY( next_cpu_cnt<=cpu_cnt ) ) {
     150           0 :       FD_LOG_WARNING(( "CPU%u out of order reading /proc/interrupts", col_cpu[ col_idx ] ));
     151           0 :       return 0;
     152           0 :     }
     153           0 :     cpu_cnt = next_cpu_cnt;
     154           0 :   }
     155           0 :   if( FD_UNLIKELY( cpu_cnt>FD_TILE_MAX ) ) {
     156           0 :     FD_LOG_WARNING(( "Too many CPUs found reading /proc/interrupts" ));
     157           0 :     return 0;
     158           0 :   }
     159             : 
     160           0 :   *out_cpu_cnt = cpu_cnt;
     161           0 :   *out_col_cnt = col_cnt;
     162           0 :   return 0;
     163           0 : }
     164             : 
     165             : ulong
     166             : fd_proc_interrupts_colwise( int   fd,
     167           0 :                             ulong per_cpu[ FD_TILE_MAX ] ) {
     168           0 :   fd_io_buffered_istream_t is[1];
     169           0 :   char buf[ 4096 ];
     170           0 :   fd_io_buffered_istream_init( is, fd, buf, sizeof(buf) );
     171             : 
     172             :   /* Read first line */
     173             : 
     174           0 :   ushort col_cpu[ FD_TILE_MAX ];
     175           0 :   ulong  col_cnt;
     176           0 :   ulong  cpu_cnt;
     177           0 :   int err = read_cpu_map( is, &col_cnt, &cpu_cnt, col_cpu );
     178           0 :   if( FD_UNLIKELY( err!=0 ) ) goto failed;
     179           0 :   if( FD_UNLIKELY( !col_cnt || !cpu_cnt ) ) return 0UL;
     180             : 
     181           0 :   for( ulong cpu=0UL; cpu<cpu_cnt; cpu++ ) {
     182           0 :     per_cpu[ cpu ] = 0UL;
     183           0 :   }
     184             : 
     185             :   /* Read interrupt table
     186             :      Device interrupt counters look like this:
     187             :      "  123:  41  42  43  44"
     188             :      Special interrupts look like this:
     189             :      "  NMI:   1   2   3   4" */
     190             : 
     191           0 :   for(;;) { /* each line */
     192             : 
     193             :     /* Read prefix */
     194           0 :     err = read_until( is, 64UL, skip_spaces );
     195           0 :     if( FD_UNLIKELY( err==-1 ) ) return cpu_cnt; /* end of input */
     196           0 :     if( FD_UNLIKELY( err!=0 ) ) goto failed;
     197           0 :     if( fd_io_buffered_istream_peek_sz( is )==0 ) return cpu_cnt;
     198           0 :     if( !isdigit( ((char const *)fd_io_buffered_istream_peek( is ))[0] ) ) {
     199             :       /* Only count numbered interrupts */
     200           0 :       goto skip_line;
     201           0 :     }
     202           0 :     err = read_until( is, 0UL, skip_token );
     203           0 :     if( FD_UNLIKELY( err!=0 ) ) goto failed;
     204             : 
     205             :     /* Read interrupt counters */
     206           0 :     for( ulong col_idx=0UL; col_idx<col_cnt; col_idx++ ) {
     207           0 :       err = read_until( is, 21UL, skip_spaces );
     208           0 :       if( FD_UNLIKELY( err!=0 ) ) goto failed;
     209             : 
     210           0 :       ulong irq_cnt = read_ulong( is );
     211           0 :       irq_cnt = fd_ulong_if( irq_cnt!=ULONG_MAX, irq_cnt, 0UL );
     212           0 :       per_cpu[ col_cpu[ col_idx ] ] += irq_cnt;
     213           0 :     }
     214             : 
     215           0 :   skip_line:
     216             :     /* Ignore rest of line */
     217           0 :     err = read_until( is, 0UL, skip_line );
     218           0 :     if( FD_UNLIKELY( err!=0 ) ) {
     219           0 :       if( err==-1 ) break;
     220           0 :       goto failed;
     221           0 :     }
     222             : 
     223           0 :   }
     224           0 :   return cpu_cnt;
     225             : 
     226           0 : failed:
     227           0 :   if( err!=0 ) {
     228           0 :     FD_LOG_WARNING(( "read failed (%i-%s)", err, fd_io_strerror( err ) ));
     229           0 :   }
     230           0 :   return 0UL;
     231           0 : }
     232             : 
     233             : /* proc_interrupts_named_row parses a single named row (e.g. "TLB:" or
     234             :    "LOC:") in /proc/interrupts.  Returns the number of CPUs found.  On
     235             :    return, per_cpu[i] contains the counter for CPU i, or 0 if the row
     236             :    was not found. */
     237             : 
     238             : static ulong
     239             : proc_interrupts_named_row( int          fd,
     240             :                            char const * row_prefix,
     241             :                            ulong        row_prefix_len,
     242           0 :                            ulong        per_cpu[ FD_TILE_MAX ] ) {
     243           0 :   fd_io_buffered_istream_t is[1];
     244           0 :   char buf[ 4096 ];
     245           0 :   fd_io_buffered_istream_init( is, fd, buf, sizeof(buf) );
     246             : 
     247           0 :   ushort col_cpu[ FD_TILE_MAX ];
     248           0 :   ulong  col_cnt;
     249           0 :   ulong  cpu_cnt;
     250           0 :   int err = read_cpu_map( is, &col_cnt, &cpu_cnt, col_cpu );
     251           0 :   if( FD_UNLIKELY( err!=0 ) ) goto failed;
     252           0 :   if( FD_UNLIKELY( !col_cnt || !cpu_cnt ) ) return 0UL;
     253             : 
     254           0 :   for( ulong cpu=0UL; cpu<cpu_cnt; cpu++ ) {
     255           0 :     per_cpu[ cpu ] = 0UL;
     256           0 :   }
     257             : 
     258           0 :   for(;;) {
     259           0 :     err = read_until( is, 64UL, skip_spaces );
     260           0 :     if( FD_UNLIKELY( err==-1 ) ) return cpu_cnt; /* end of input */
     261           0 :     if( FD_UNLIKELY( err!=0 ) ) goto failed;
     262           0 :     if( fd_io_buffered_istream_peek_sz( is )==0 ) return cpu_cnt;
     263             : 
     264           0 :     char const * prefix     = fd_io_buffered_istream_peek   ( is );
     265           0 :     ulong        prefix_max = fd_io_buffered_istream_peek_sz( is );
     266           0 :     if( FD_UNLIKELY( prefix_max>=row_prefix_len && fd_memeq( prefix, row_prefix, row_prefix_len ) ) ) {
     267           0 :       err = read_until( is, 0UL, skip_token );
     268           0 :       if( FD_UNLIKELY( err!=0 ) ) goto failed;
     269             : 
     270           0 :       for( ulong col_idx=0UL; col_idx<col_cnt; col_idx++ ) {
     271           0 :         err = read_until( is, 21UL, skip_spaces );
     272           0 :         if( FD_UNLIKELY( err!=0 ) ) goto failed;
     273             : 
     274           0 :         ulong irq_cnt = read_ulong( is );
     275           0 :         irq_cnt = fd_ulong_if( irq_cnt!=ULONG_MAX, irq_cnt, 0UL );
     276           0 :         per_cpu[ col_cpu[ col_idx ] ] = irq_cnt;
     277           0 :       }
     278           0 :       return cpu_cnt;
     279           0 :     }
     280             : 
     281           0 :     err = read_until( is, 0UL, skip_line );
     282           0 :     if( FD_UNLIKELY( err!=0 ) ) {
     283           0 :       if( err==-1 ) break;
     284           0 :       goto failed;
     285           0 :     }
     286           0 :   }
     287           0 :   return cpu_cnt;
     288             : 
     289           0 : failed:
     290           0 :   if( err!=0 ) {
     291           0 :     FD_LOG_WARNING(( "read failed (%i-%s)", err, fd_io_strerror( err ) ));
     292           0 :   }
     293           0 :   return 0UL;
     294           0 : }
     295             : 
     296             : ulong
     297             : fd_proc_interrupts_tlb( int   fd,
     298           0 :                         ulong per_cpu[ FD_TILE_MAX ] ) {
     299           0 :   return proc_interrupts_named_row( fd, "TLB:", 4UL, per_cpu );
     300           0 : }
     301             : 
     302             : ulong
     303             : fd_proc_interrupts_loc( int   fd,
     304           0 :                         ulong per_cpu[ FD_TILE_MAX ] ) {
     305           0 :   return proc_interrupts_named_row( fd, "LOC:", 4UL, per_cpu );
     306           0 : }
     307             : 
     308             : ulong
     309             : fd_proc_softirqs_sum( int   fd,
     310           0 :                       ulong per_cpu[ FD_METRICS_ENUM_SOFTIRQ_CNT ][ FD_TILE_MAX ] ) {
     311           0 :   fd_io_buffered_istream_t is[1];
     312           0 :   char buf[ 4096 ];
     313           0 :   fd_io_buffered_istream_init( is, fd, buf, sizeof(buf) );
     314             : 
     315             :   /* Read first line */
     316             : 
     317           0 :   ushort col_cpu[ FD_TILE_MAX ];
     318           0 :   ulong  col_cnt;
     319           0 :   ulong  cpu_cnt;
     320           0 :   int err = read_cpu_map( is, &col_cnt, &cpu_cnt, col_cpu );
     321           0 :   if( FD_UNLIKELY( err!=0 ) ) goto failed;
     322           0 :   if( FD_UNLIKELY( !col_cnt || !cpu_cnt ) ) return 0UL;
     323           0 :   for( ulong i=0UL; i<FD_METRICS_ENUM_SOFTIRQ_CNT; i++ ) {
     324           0 :     for( ulong c=0UL; c<cpu_cnt; c++ ) per_cpu[ i ][ c ] = 0UL;
     325           0 :   }
     326             : 
     327             :   /* Read softirq table
     328             :      Looks like this:
     329             :      "   NET_TX:   1   2   3   5" */
     330             : 
     331           0 :   for(;;) { /* each line */
     332             : 
     333             :     /* Read prefix */
     334           0 :     err = read_until( is, 64UL, skip_spaces );
     335           0 :     if( FD_UNLIKELY( err==-1 ) ) return cpu_cnt; /* end of input */
     336           0 :     if( FD_UNLIKELY( err!=0 ) ) goto failed;
     337           0 :     if( fd_io_buffered_istream_peek_sz( is )==0 ) return cpu_cnt;
     338             : 
     339             :     /* Match prefix */
     340           0 :     int          kind       = FD_METRICS_ENUM_SOFTIRQ_V_OTHER_IDX;
     341           0 :     char const * prefix     = fd_io_buffered_istream_peek   ( is );
     342           0 :     ulong        prefix_max = fd_io_buffered_istream_peek_sz( is );
     343           0 :     if( prefix_max>=7 && fd_memeq( prefix, "NET_TX:", 7 ) ) {
     344           0 :       kind = FD_METRICS_ENUM_SOFTIRQ_V_NET_IDX;
     345           0 :     } else if( prefix_max>=7 && fd_memeq( prefix, "NET_RX:", 7 ) ) {
     346           0 :       kind = FD_METRICS_ENUM_SOFTIRQ_V_NET_IDX;
     347           0 :     } else if( prefix_max>=6 && fd_memeq( prefix, "BLOCK:", 6 ) ) {
     348           0 :       kind = FD_METRICS_ENUM_SOFTIRQ_V_DISK_IDX;
     349           0 :     }
     350           0 :     err = read_until( is, 0UL, skip_token );
     351           0 :     if( FD_UNLIKELY( err!=0 ) ) goto failed;
     352             : 
     353             :     /* Read interrupt counters */
     354           0 :     for( ulong col_idx=0UL; col_idx<col_cnt; col_idx++ ) {
     355           0 :       err = read_until( is, 21UL, skip_spaces );
     356           0 :       if( FD_UNLIKELY( err!=0 ) ) goto failed;
     357             : 
     358           0 :       ulong irq_cnt = read_ulong( is );
     359           0 :       irq_cnt = fd_ulong_if( irq_cnt!=ULONG_MAX, irq_cnt, 0UL );
     360           0 :       per_cpu[ kind ][ col_cpu[ col_idx ] ] += irq_cnt;
     361           0 :     }
     362             : 
     363             :     /* Ignore rest of line */
     364           0 :     err = read_until( is, 0UL, skip_line );
     365           0 :     if( FD_UNLIKELY( err!=0 ) ) {
     366           0 :       if( err==-1 ) break;
     367           0 :       goto failed;
     368           0 :     }
     369             : 
     370           0 :   }
     371           0 :   return cpu_cnt;
     372             : 
     373           0 : failed:
     374           0 :   if( err!=0 ) {
     375           0 :     FD_LOG_WARNING(( "read failed (%i-%s)", err, fd_io_strerror( err ) ));
     376           0 :   }
     377           0 :   return 0UL;
     378           0 : }
     379             : 
     380             : ulong
     381             : fd_proc_stat_irq_ticks( int   fd,
     382           0 :                         ulong per_cpu[ FD_TILE_MAX ] ) {
     383           0 :   fd_io_buffered_istream_t is[1];
     384           0 :   char buf[ 4096 ];
     385           0 :   fd_io_buffered_istream_init( is, fd, buf, sizeof(buf) );
     386             : 
     387           0 :   for( ulong cpu=0UL; cpu<FD_TILE_MAX; cpu++ ) {
     388           0 :     per_cpu[ cpu ] = 0UL;
     389           0 :   }
     390             : 
     391             :   /* Per-CPU rows look like this ("cpu" summary row has no digit):
     392             :      "cpu7 134688 9390 52162 76129767 4217 3283 2069 0 0 0"
     393             :      Fields after the cpuN token: user nice system idle iowait irq
     394             :      softirq steal guest guest_nice. */
     395             : 
     396           0 :   ulong cpu_cnt = 0UL;
     397           0 :   int   err;
     398           0 :   for(;;) {
     399           0 :     err = read_until( is, 64UL, skip_spaces );
     400           0 :     if( FD_UNLIKELY( err==-1 ) ) return cpu_cnt; /* end of input */
     401           0 :     if( FD_UNLIKELY( err!=0 ) ) goto failed;
     402           0 :     if( fd_io_buffered_istream_peek_sz( is )==0 ) return cpu_cnt;
     403             : 
     404           0 :     char const * prefix     = fd_io_buffered_istream_peek   ( is );
     405           0 :     ulong        prefix_max = fd_io_buffered_istream_peek_sz( is );
     406             : 
     407             :     /* Rows are ordered: "cpu", "cpu0".."cpuN", then non-cpu rows.  Stop
     408             :        at the first non-cpu row. */
     409           0 :     if( FD_UNLIKELY( prefix_max<4UL || !fd_memeq( prefix, "cpu", 3UL ) ) ) return cpu_cnt;
     410           0 :     if( FD_UNLIKELY( !isdigit( prefix[ 3 ] ) ) ) { /* "cpu" summary row */
     411           0 :       err = read_until( is, 0UL, skip_line );
     412           0 :       if( FD_UNLIKELY( err!=0 ) ) { if( err==-1 ) break; goto failed; }
     413           0 :       continue;
     414           0 :     }
     415             : 
     416           0 :     fd_io_buffered_istream_skip( is, 3UL );
     417           0 :     ulong cpu_idx = read_ulong( is );
     418           0 :     if( FD_UNLIKELY( cpu_idx==ULONG_MAX ) ) {
     419           0 :       FD_LOG_WARNING(( "failed to parse cpu index in /proc/stat" ));
     420           0 :       return 0UL;
     421           0 :     }
     422             : 
     423             :     /* Sum fields 6 (irq), 7 (softirq) and 8 (steal), 1-indexed after
     424             :        the cpuN token. */
     425           0 :     ulong ticks = 0UL;
     426           0 :     for( ulong field_idx=1UL; field_idx<=8UL; field_idx++ ) {
     427           0 :       err = read_until( is, 21UL, skip_spaces );
     428           0 :       if( FD_UNLIKELY( err!=0 ) ) goto failed;
     429             : 
     430           0 :       ulong val = read_ulong( is );
     431           0 :       val = fd_ulong_if( val!=ULONG_MAX, val, 0UL );
     432           0 :       if( field_idx>=6UL ) ticks += val;
     433           0 :     }
     434           0 :     if( FD_LIKELY( cpu_idx<FD_TILE_MAX ) ) {
     435           0 :       per_cpu[ cpu_idx ] = ticks;
     436           0 :       cpu_cnt = fd_ulong_max( cpu_cnt, cpu_idx+1UL );
     437           0 :     }
     438             : 
     439           0 :     err = read_until( is, 0UL, skip_line );
     440           0 :     if( FD_UNLIKELY( err!=0 ) ) {
     441           0 :       if( err==-1 ) break;
     442           0 :       goto failed;
     443           0 :     }
     444           0 :   }
     445           0 :   return cpu_cnt;
     446             : 
     447           0 : failed:
     448           0 :   if( err!=0 ) {
     449           0 :     FD_LOG_WARNING(( "read failed (%i-%s)", err, fd_io_strerror( err ) ));
     450           0 :   }
     451           0 :   return 0UL;
     452           0 : }

Generated by: LCOV version 1.14