LCOV - code coverage report
Current view: top level - disco/topo - fd_cpu_topo.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 63 73 86.3 %
Date: 2025-03-20 12:08:36 Functions: 5 6 83.3 %

          Line data    Source code
       1             : #include "fd_cpu_topo.h"
       2             : 
       3             : #include "../../util/shmem/fd_shmem_private.h"
       4             : 
       5             : #include <errno.h>
       6             : #include <unistd.h>
       7             : #include <fcntl.h>
       8             : #include <stdio.h>
       9             : #include <stdlib.h>
      10             : 
      11             : static uint
      12             : read_uint_file( char const * path,
      13         378 :                 char const * errmsg_enoent ) {
      14         378 :   FILE * fp = fopen( path, "r" );
      15         378 :   if( FD_UNLIKELY( !fp ) ) {
      16           0 :     if( FD_LIKELY( errno==ENOENT ) ) FD_LOG_ERR(( "%s fopen failed `%s` (%i-%s)", errmsg_enoent, path, errno, fd_io_strerror( errno ) ));
      17           0 :     else                             FD_LOG_ERR(( "fopen failed `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      18           0 :   }
      19             : 
      20         378 :   uint value = 0U;
      21         378 :   if( FD_UNLIKELY( 1!=fscanf( fp, "%u\n", &value ) ) ) FD_LOG_ERR(( "failed to read uint from `%s`", path ));
      22         378 :   if( FD_UNLIKELY( fclose( fp ) ) ) FD_LOG_ERR(( "fclose failed `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      23         378 :   return value;
      24         378 : }
      25             : 
      26             : static ulong
      27           6 : fd_topo_cpu_cnt( void ) {
      28           6 :   char path[ PATH_MAX ];
      29           6 :   fd_cstr_printf_check( path, PATH_MAX, NULL, "/sys/devices/system/cpu/present" );
      30             : 
      31           6 :   char line[ 128 ];
      32           6 :   int fd = open( path, O_RDONLY );
      33           6 :   if( FD_UNLIKELY( -1==fd ) ) FD_LOG_ERR(( "open( \"%s\" ) failed (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      34             : 
      35           6 :   long bytes_read = read( fd, line, sizeof( line ) );
      36           6 :   if( FD_UNLIKELY( -1==bytes_read ) ) FD_LOG_ERR(( "read( \"%s\" ) failed (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      37           6 :   else if ( FD_UNLIKELY( (ulong)bytes_read>=sizeof( line ) ) ) FD_LOG_ERR(( "read( \"%s\" ) failed: buffer too small", path ));
      38             : 
      39           6 :   if( FD_UNLIKELY( close( fd ) ) ) FD_LOG_ERR(( "close( \"%s\" ) failed (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      40             : 
      41           6 :   line[ bytes_read ] = '\0';
      42           6 :   char * saveptr;
      43           6 :   char * token = strtok_r( line, "-", &saveptr );
      44           6 :   token = strtok_r( NULL, "-", &saveptr );
      45           6 :   ulong end = fd_cstr_to_ulong( token );
      46             : 
      47           6 :   return end+1UL;
      48           6 : }
      49             : 
      50             : /* Return the sibling CPU (hyperthreaded pair) of the provided CPU, if
      51             :    there is one, otherwise return ULONG_MAX.  On error, logs an error
      52             :    and exits the process. */
      53             : 
      54             : ulong
      55         384 : fd_topob_sibling_idx( ulong cpu_idx ) {
      56         384 :   char path[ PATH_MAX ];
      57         384 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/sys/devices/system/cpu/cpu%lu/topology/thread_siblings_list", cpu_idx ) );
      58             : 
      59         384 :   int fd = open( path, O_RDONLY );
      60         384 :   if( FD_UNLIKELY( -1==fd ) ) FD_LOG_ERR(( "open( \"%s\" ) failed (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      61             : 
      62         384 :   char line[ 1024 ] = {0};
      63         384 :   long bytes_read = read( fd, line, sizeof( line ) );
      64         384 :   if( FD_UNLIKELY( -1==bytes_read ) ) FD_LOG_ERR(( "read( \"%s\" ) failed (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      65         384 :   else if ( FD_UNLIKELY( (ulong)bytes_read>=sizeof( line ) ) ) FD_LOG_ERR(( "read( \"%s\" ) failed: buffer too small", path ));
      66             : 
      67         384 :   if( FD_UNLIKELY( close( fd ) ) ) FD_LOG_ERR(( "close( \"%s\" ) failed (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      68             : 
      69         384 :   char * sep = strchr( line, ',' );
      70         384 :   if( FD_UNLIKELY( !sep ) ) return ULONG_MAX;
      71             : 
      72         384 :   *sep = '\0';
      73         384 :   errno = 0;
      74         384 :   char * endptr;
      75         384 :   ulong pair1 = strtoul( line, &endptr, 10 );
      76         384 :   if( FD_UNLIKELY( *endptr!='\0' || errno==ERANGE || errno==EINVAL ) ) FD_LOG_ERR(( "failed to parse cpu siblings list of cpu%lu `%s`", cpu_idx, line ));
      77             : 
      78         384 :   ulong pair2 = strtoul( sep+1UL, &endptr, 10 );
      79         384 :   if( FD_UNLIKELY( *endptr!='\n' || errno==ERANGE || errno==EINVAL ) ) FD_LOG_ERR(( "failed to parse cpu siblings list of cpu%lu `%s`", pair1, sep+1UL ));
      80             : 
      81         384 :   if( FD_LIKELY( pair1==cpu_idx ) )      return pair2;
      82         192 :   else if( FD_LIKELY( pair2==cpu_idx ) ) return pair1;
      83           0 :   else FD_LOG_ERR(( "failed to find sibling of cpu%lu", cpu_idx ));
      84         384 : }
      85             : 
      86             : static int
      87         384 : fd_topo_cpus_online( ulong cpu_idx ) {
      88         384 :   if( FD_UNLIKELY( cpu_idx==0UL ) ) return 1; /* Cannot set cpu0 to offline */
      89             : 
      90         378 :   char path[ PATH_MAX ];
      91         378 :   FD_TEST( fd_cstr_printf_check( path, sizeof( path ), NULL, "/sys/devices/system/cpu/cpu%lu/online", cpu_idx ) );
      92         378 :   return (int)read_uint_file( path, "error reading cpu online status" );
      93         378 : }
      94             : 
      95             : void
      96           6 : fd_topo_cpus_init( fd_topo_cpus_t * cpus ) {
      97           6 :   cpus->numa_node_cnt = fd_numa_node_cnt();
      98           6 :   cpus->cpu_cnt = fd_topo_cpu_cnt();
      99             : 
     100         390 :   for( ulong i=0UL; i<cpus->cpu_cnt; i++ ) {
     101         384 :     cpus->cpu[ i ].idx = i;
     102         384 :     cpus->cpu[ i ].online = fd_topo_cpus_online( i );
     103         384 :     cpus->cpu[ i ].numa_node = fd_numa_node_idx( i );
     104         384 :     if( FD_LIKELY( cpus->cpu[ i ].online ) ) cpus->cpu[ i ].sibling = fd_topob_sibling_idx( i );
     105           0 :     else                                     cpus->cpu[ i ].sibling = ULONG_MAX;
     106         384 :   }
     107           6 : }
     108             : 
     109             : void
     110           0 : fd_topo_cpus_printf( fd_topo_cpus_t * cpus ) {
     111           0 :   for( ulong i=0UL; i<cpus->cpu_cnt; i++ ) {
     112           0 :     FD_LOG_NOTICE(( "cpu%lu: online=%i sibling=%lu numa_node=%lu", i, cpus->cpu[ i ].online, cpus->cpu[ i ].sibling, cpus->cpu[ i ].numa_node ));
     113           0 :   }
     114           0 : }

Generated by: LCOV version 1.14