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 : }
|