LCOV - code coverage report
Current view: top level - disco/diag - fd_diag_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 292 0.0 %
Date: 2026-02-13 06:06:24 Functions: 0 10 0.0 %

          Line data    Source code
       1             : #include "../metrics/fd_metrics.h"
       2             : #include "../stem/fd_stem.h"
       3             : #include "../topo/fd_topo.h"
       4             : 
       5             : #include <fcntl.h>
       6             : #include <errno.h>
       7             : #include <stdlib.h>
       8             : #include <sys/types.h> /* SEEK_SET */
       9             : #include <time.h>
      10             : #include <unistd.h>
      11             : 
      12             : #include "generated/fd_diag_tile_seccomp.h"
      13             : 
      14           0 : #define REPORT_INTERVAL_MILLIS (100L)
      15             : 
      16             : struct fd_diag_tile {
      17             :   long next_report_nanos;
      18             : 
      19             :   ulong tile_cnt;
      20             : 
      21             :   ulong starttime_nanos[ FD_TILE_MAX ];
      22             :   long  first_seen_died[ FD_TILE_MAX ];
      23             : 
      24             :   int stat_fds[ FD_TILE_MAX ];
      25             :   int sched_fds[ FD_TILE_MAX ];
      26             : 
      27             :   volatile ulong * metrics[ FD_TILE_MAX ];
      28             : };
      29             : 
      30             : typedef struct fd_diag_tile fd_diag_tile_t;
      31             : 
      32             : FD_FN_CONST static inline ulong
      33           0 : scratch_align( void ) {
      34           0 :   return 128UL;
      35           0 : }
      36             : 
      37             : FD_FN_PURE static inline ulong
      38           0 : scratch_footprint( fd_topo_tile_t const * tile ) {
      39           0 :   (void)tile;
      40           0 :   ulong l = FD_LAYOUT_INIT;
      41           0 :   l = FD_LAYOUT_APPEND( l, alignof( fd_diag_tile_t ), sizeof( fd_diag_tile_t ) );
      42           0 :   return FD_LAYOUT_FINI( l, scratch_align() );
      43           0 : }
      44             : 
      45             : static int
      46             : read_stat_file( int              fd,
      47             :                 ulong            ns_per_tick,
      48           0 :                 volatile ulong * metrics ) {
      49           0 :   if( FD_UNLIKELY( -1==lseek( fd, 0, SEEK_SET ) ) ) FD_LOG_ERR(( "lseek failed (%i-%s)", errno, strerror( errno ) ));
      50             : 
      51           0 :   char contents[ 4096 ] = {0};
      52           0 :   ulong contents_len = 0UL;
      53             : 
      54           0 :   while( 1 ) {
      55           0 :     if( FD_UNLIKELY( contents_len>=sizeof( contents ) ) ) FD_LOG_ERR(( "stat contents overflow" ));
      56           0 :     long n = read( fd, contents + contents_len, sizeof( contents ) - contents_len );
      57           0 :     if( FD_UNLIKELY( -1==n ) ) {
      58           0 :       if( FD_UNLIKELY( errno==ESRCH ) ) return 1;
      59           0 :       FD_LOG_ERR(( "read failed (%i-%s)", errno, strerror( errno ) ));
      60           0 :     }
      61           0 :     if( FD_LIKELY( 0==n ) ) break;
      62           0 :     contents_len += (ulong)n;
      63           0 :   }
      64             : 
      65             :   /* Parse stat file: fields are space-separated.
      66             :      Field 10 (1-indexed) = minflt, field 12 = majflt,
      67             :      field 14 = utime, field 15 = stime (all in clock ticks). */
      68           0 :   char * saveptr;
      69           0 :   char * token = strtok_r( contents, " ", &saveptr );
      70           0 :   ulong field_idx = 0UL;
      71             : 
      72           0 :   while( token ) {
      73           0 :     if( FD_UNLIKELY( 9UL==field_idx ) ) {
      74           0 :       char * endptr;
      75           0 :       ulong minflt = strtoul( token, &endptr, 10 );
      76           0 :       if( FD_UNLIKELY( *endptr!='\0' || minflt==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul failed for minflt" ));
      77           0 :       metrics[ FD_METRICS_COUNTER_TILE_PAGE_FAULT_MINOR_COUNT_OFF ] = minflt;
      78           0 :     } else if( FD_UNLIKELY( 11UL==field_idx ) ) {
      79           0 :       char * endptr;
      80           0 :       ulong majflt = strtoul( token, &endptr, 10 );
      81           0 :       if( FD_UNLIKELY( *endptr!='\0' || majflt==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul failed for majflt" ));
      82           0 :       metrics[ FD_METRICS_COUNTER_TILE_PAGE_FAULT_MAJOR_COUNT_OFF ] = majflt;
      83           0 :     } else if( FD_UNLIKELY( 13UL==field_idx ) ) {
      84           0 :       char * endptr;
      85           0 :       ulong utime_ticks = strtoul( token, &endptr, 10 );
      86           0 :       if( FD_UNLIKELY( *endptr!='\0' || utime_ticks==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul failed for utime" ));
      87           0 :       metrics[ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_USER_OFF ] = utime_ticks*ns_per_tick;
      88           0 :     } else if( FD_UNLIKELY( 14UL==field_idx ) ) {
      89           0 :       char * endptr;
      90           0 :       ulong stime_ticks = strtoul( token, &endptr, 10 );
      91           0 :       if( FD_UNLIKELY( *endptr!='\0' || stime_ticks==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul failed for stime" ));
      92           0 :       metrics[ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_SYSTEM_OFF ] = stime_ticks*ns_per_tick;
      93           0 :     } else if( FD_UNLIKELY( 39UL==field_idx ) ) {
      94           0 :       char * endptr;
      95           0 :       ulong last_cpu_ticks = strtoul( token, &endptr, 10 );
      96           0 :       if( FD_UNLIKELY( *endptr!='\0' || last_cpu_ticks==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul failed for processor" ));
      97           0 :       metrics[ FD_METRICS_GAUGE_TILE_LAST_CPU_OFF ] = last_cpu_ticks*ns_per_tick;
      98           0 :       break; /* No need to parse stat further */
      99           0 :     }
     100           0 :     token = strtok_r( NULL, " ", &saveptr );
     101           0 :     field_idx++;
     102           0 :   }
     103             : 
     104           0 :   if( FD_UNLIKELY( field_idx!=39UL ) ) FD_LOG_ERR(( "failed to parse /proc/<pid>/task/<tid>/stat" ));
     105             : 
     106           0 :   return 0;
     107           0 : }
     108             : 
     109             : static int
     110             : read_sched_file( int              fd,
     111           0 :                  volatile ulong * metrics ) {
     112           0 :   if( FD_UNLIKELY( -1==lseek( fd, 0, SEEK_SET ) ) ) FD_LOG_ERR(( "lseek failed (%i-%s)", errno, strerror( errno ) ));
     113             : 
     114           0 :   char contents[ 8192 ] = {0};
     115           0 :   ulong contents_len = 0UL;
     116             : 
     117           0 :   while( 1 ) {
     118           0 :     if( FD_UNLIKELY( contents_len>=sizeof( contents ) ) ) FD_LOG_ERR(( "sched contents overflow" ));
     119           0 :     long n = read( fd, contents + contents_len, sizeof( contents ) - contents_len );
     120           0 :     if( FD_UNLIKELY( -1==n ) ) {
     121           0 :       if( FD_UNLIKELY( errno==ESRCH ) ) return 1;
     122           0 :       FD_LOG_ERR(( "read failed (%i-%s)", errno, strerror( errno ) ));
     123           0 :     }
     124           0 :     if( FD_LIKELY( 0==n ) ) break;
     125           0 :     contents_len += (ulong)n;
     126           0 :   }
     127             : 
     128           0 :   int found_wait_sum = 0;
     129           0 :   int found_voluntary = 0;
     130           0 :   int found_involuntary = 0;
     131             : 
     132           0 :   char * line = contents;
     133           0 :   while( 1 ) {
     134           0 :     char * next_line = strchr( line, '\n' );
     135           0 :     if( FD_UNLIKELY( NULL==next_line ) ) break;
     136           0 :     *next_line = '\0';
     137             : 
     138           0 :     if( FD_UNLIKELY( !strncmp( line, "wait_sum", 8UL ) ) ) {
     139           0 :       char * colon = strchr( line, ':' );
     140           0 :       if( FD_LIKELY( colon ) ) {
     141           0 :         char * value = colon + 1;
     142           0 :         while( ' '==*value || '\t'==*value ) value++;
     143             :         /* wait_sum is displayed as seconds.microseconds (e.g., "123.456789").
     144             :            Parse both components as integers and convert to nanoseconds. */
     145           0 :         char * endptr;
     146           0 :         ulong seconds = strtoul( value, &endptr, 10 );
     147           0 :         if( FD_UNLIKELY( '.'!=*endptr ) ) FD_LOG_ERR(( "expected '.' after seconds in wait_sum" ));
     148           0 :         if( FD_UNLIKELY( seconds==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul overflow for wait_sum seconds" ));
     149           0 :         ulong microseconds = strtoul( endptr + 1, &endptr, 10 );
     150           0 :         if( FD_UNLIKELY( '\0'!=*endptr ) ) FD_LOG_ERR(( "unexpected char after microseconds in wait_sum" ));
     151           0 :         if( FD_UNLIKELY( microseconds==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul overflow for wait_sum microseconds" ));
     152           0 :         ulong wait_sum_ns = seconds*1000000000UL + microseconds*1000UL;
     153           0 :         metrics[ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_WAIT_OFF ] = wait_sum_ns;
     154           0 :         found_wait_sum = 1;
     155           0 :       }
     156           0 :     } else if( FD_UNLIKELY( !strncmp( line, "nr_voluntary_switches", 21UL ) ) ) {
     157           0 :       char * colon = strchr( line, ':' );
     158           0 :       if( FD_LIKELY( colon ) ) {
     159           0 :         char * value = colon + 1;
     160           0 :         while( ' '==*value || '\t'==*value ) value++;
     161           0 :         char * endptr;
     162           0 :         ulong voluntary_switches = strtoul( value, &endptr, 10 );
     163           0 :         if( FD_UNLIKELY( '\0'!=*endptr ) ) FD_LOG_ERR(( "unexpected char after nr_voluntary_switches" ));
     164           0 :         if( FD_UNLIKELY( voluntary_switches==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul overflow for nr_voluntary_switches" ));
     165           0 :         metrics[ FD_METRICS_COUNTER_TILE_CONTEXT_SWITCH_VOLUNTARY_COUNT_OFF ] = voluntary_switches;
     166           0 :         found_voluntary = 1;
     167           0 :       }
     168           0 :     } else if( FD_UNLIKELY( !strncmp( line, "nr_involuntary_switches", 23UL ) ) ) {
     169           0 :       char * colon = strchr( line, ':' );
     170           0 :       if( FD_LIKELY( colon ) ) {
     171           0 :         char * value = colon + 1;
     172           0 :         while( ' '==*value || '\t'==*value ) value++;
     173           0 :         char * endptr;
     174           0 :         ulong involuntary_switches = strtoul( value, &endptr, 10 );
     175           0 :         if( FD_UNLIKELY( '\0'!=*endptr ) ) FD_LOG_ERR(( "unexpected char after nr_involuntary_switches" ));
     176           0 :         if( FD_UNLIKELY( involuntary_switches==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul overflow for nr_involuntary_switches" ));
     177           0 :         metrics[ FD_METRICS_COUNTER_TILE_CONTEXT_SWITCH_INVOLUNTARY_COUNT_OFF ] = involuntary_switches;
     178           0 :         found_involuntary = 1;
     179           0 :       }
     180           0 :     }
     181             : 
     182           0 :     line = next_line + 1;
     183           0 :   }
     184             : 
     185             :   // wait_sum not present on kernels compiled without CONFIG_SCHEDSTATS=y
     186             :   // if( FD_UNLIKELY( !found_wait_sum ) ) FD_LOG_ERR(( "wait_sum not found in sched file" ));
     187           0 :   (void)found_wait_sum;
     188           0 :   if( FD_UNLIKELY( !found_voluntary ) ) FD_LOG_ERR(( "nr_voluntary_switches not found in sched file" ));
     189           0 :   if( FD_UNLIKELY( !found_involuntary ) ) FD_LOG_ERR(( "nr_involuntary_switches not found in sched file" ));
     190             : 
     191           0 :   return 0;
     192           0 : }
     193             : 
     194             : static void
     195             : before_credit( fd_diag_tile_t *    ctx,
     196             :                fd_stem_context_t * stem,
     197           0 :                int *               charge_busy ) {
     198           0 :   (void)stem;
     199             : 
     200           0 :   long now = fd_log_wallclock();
     201           0 :   if( now<ctx->next_report_nanos ) {
     202           0 :     long diff = ctx->next_report_nanos - now;
     203           0 :     diff = fd_long_min( diff, 2e6 /* 2ms */ );
     204           0 :     struct timespec const ts = {
     205           0 :       .tv_sec  = diff / (long)1e9,
     206           0 :       .tv_nsec = diff % (long)1e9
     207           0 :     };
     208           0 :     clock_nanosleep( CLOCK_REALTIME, 0, &ts, NULL );
     209           0 :     return;
     210           0 :   }
     211           0 :   ctx->next_report_nanos += REPORT_INTERVAL_MILLIS*1000L*1000L;
     212             : 
     213           0 :   *charge_busy = 1;
     214             : 
     215           0 :   struct timespec boottime;
     216           0 :   if( FD_UNLIKELY( -1==clock_gettime( CLOCK_BOOTTIME, &boottime ) ) ) FD_LOG_ERR(( "clock_gettime(CLOCK_BOOTTIME) failed (%i-%s)", errno, strerror( errno ) ));
     217           0 :   ulong now_since_boot_nanos = (ulong)boottime.tv_sec*1000000000UL + (ulong)boottime.tv_nsec;
     218             : 
     219           0 :   for( ulong i=0UL; i<ctx->tile_cnt; i++ ) {
     220           0 :     if( FD_UNLIKELY( -1==ctx->stat_fds[ i ] ) ) continue;
     221             : 
     222             :     /* CLK_TCK is typically 100, so 1 tick = 10ms = 10,000,000 ns */
     223           0 :     int process_died1 = read_stat_file( ctx->stat_fds[ i ], 10000000UL, ctx->metrics[ i ] );
     224           0 :     int process_died2 = read_sched_file( ctx->sched_fds[ i ], ctx->metrics[ i ] );
     225             : 
     226           0 :     if( FD_UNLIKELY( process_died1 || process_died2 ) ) {
     227           0 :       ctx->stat_fds[ i ] = -1;
     228           0 :       continue;
     229           0 :     }
     230             : 
     231           0 :     ulong task_lifetime_nanos = now_since_boot_nanos - ctx->starttime_nanos[ i ];
     232           0 :     ulong user_nanos   = ctx->metrics[ i ][ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_USER_OFF ];
     233           0 :     ulong system_nanos = ctx->metrics[ i ][ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_SYSTEM_OFF ];
     234           0 :     ulong wait_nanos   = ctx->metrics[ i ][ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_WAIT_OFF ];
     235           0 :     ulong busy_nanos   = user_nanos+system_nanos+wait_nanos;
     236           0 :     ulong idle_nanos   = (task_lifetime_nanos>busy_nanos) ? (task_lifetime_nanos-busy_nanos) : 0UL;
     237             : 
     238             :     /* Counter can't go backwards in Prometheus else it thinks the
     239             :        application restarted.  Use max to ensure monotonicity. */
     240           0 :     ctx->metrics[ i ][ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_IDLE_OFF ] = fd_ulong_max( idle_nanos, ctx->metrics[ i ][ FD_METRICS_COUNTER_TILE_CPU_DURATION_NANOS_IDLE_OFF ] );
     241           0 :   }
     242             : 
     243           0 :   for( ulong i=0UL; i<ctx->tile_cnt; i++ ) {
     244           0 :     if( FD_LIKELY( -1!=ctx->stat_fds[ i ] ) ) continue;
     245             : 
     246             :     /* The tile died, but it's a tile which is allowed to shutdown, so
     247             :        just stop updating metrics for it. */
     248           0 :     if( FD_LIKELY( 2UL==ctx->metrics[ i ][ FD_METRICS_GAUGE_TILE_STATUS_OFF ] ) ) continue;
     249             : 
     250             :     /* Supervisor is going to bring the whole process tree down if any
     251             :        of the target PIDs died, so we can ignore this and wait. */
     252           0 :     if( FD_UNLIKELY( !ctx->first_seen_died[ i ] ) ) {
     253           0 :       ctx->first_seen_died[ i ] = now;
     254           0 :     } else if( FD_LIKELY( ctx->first_seen_died[ i ]==LONG_MAX ) ) {
     255             :       /* We already reported this, so we can ignore it. */
     256           0 :     } else if( FD_UNLIKELY( now-ctx->first_seen_died[ i ] < 10L*1000L*1000L*1000L ) ) {
     257             :       /* Wait 10 seconds for supervisor to kill us before reporting WARNING */
     258           0 :     } else {
     259           0 :       FD_LOG_WARNING(( "cannot get metrics for dead tile idx %lu", i ));
     260           0 :       ctx->first_seen_died[ i ] = LONG_MAX;
     261           0 :     }
     262           0 :   }
     263           0 : }
     264             : 
     265             : static void
     266             : privileged_init( fd_topo_t *      topo,
     267           0 :                  fd_topo_tile_t * tile ) {
     268           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     269             : 
     270           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     271           0 :   fd_diag_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_diag_tile_t), sizeof(fd_diag_tile_t) );
     272             : 
     273           0 :   FD_TEST( topo->tile_cnt<FD_TILE_MAX );
     274             : 
     275           0 :   FD_TEST( 100L == sysconf( _SC_CLK_TCK ) );
     276             : 
     277           0 :   ctx->tile_cnt = topo->tile_cnt;
     278           0 :   for( ulong i=0UL; i<FD_TILE_MAX; i++ ) {
     279           0 :     ctx->stat_fds[ i ]  = -1;
     280           0 :     ctx->sched_fds[ i ] = -1;
     281           0 :   }
     282             : 
     283           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
     284           0 :     ulong * metrics = fd_metrics_join( fd_topo_obj_laddr( topo, topo->tiles[ i ].metrics_obj_id ) );
     285             : 
     286           0 :     for(;;) {
     287           0 :       ulong pid, tid;
     288           0 :       if( FD_UNLIKELY( tile->id==i ) ) {
     289           0 :         pid = fd_sandbox_getpid();
     290           0 :         tid = fd_sandbox_gettid();
     291           0 :       } else {
     292           0 :         pid = fd_metrics_tile( metrics )[ FD_METRICS_GAUGE_TILE_PID_OFF ];
     293           0 :         tid = fd_metrics_tile( metrics )[ FD_METRICS_GAUGE_TILE_TID_OFF ];
     294           0 :         if( FD_UNLIKELY( !pid || !tid ) ) {
     295           0 :           FD_SPIN_PAUSE();
     296           0 :           continue;
     297           0 :         }
     298           0 :       }
     299             : 
     300           0 :       ctx->metrics[ i ] = fd_metrics_tile( metrics );
     301             : 
     302           0 :       char path[ 64UL ];
     303           0 :       FD_TEST( fd_cstr_printf_check( path, sizeof( path ), NULL, "/proc/%lu/task/%lu/stat", pid, tid ) );
     304           0 :       ctx->stat_fds[ i ] = open( path, O_RDONLY );
     305           0 :       if( FD_UNLIKELY( -1==ctx->stat_fds[ i ] ) ) {
     306             :         /* Might be a tile that's allowed to shutdown already did so
     307             :            before we got to here, due to a race condition.  Just
     308             :            proceed, we will not be able to get metrics for the shut
     309             :            down process. */
     310           0 :         if( FD_LIKELY( 2UL!=ctx->metrics[ i ][ FD_METRICS_GAUGE_TILE_STATUS_OFF ] ) ) FD_LOG_ERR(( "open stat failed (%i-%s)", errno, strerror( errno ) ));
     311           0 :         break;
     312           0 :       }
     313             : 
     314           0 :       FD_TEST( fd_cstr_printf_check( path, sizeof( path ), NULL, "/proc/%lu/task/%lu/sched", pid, tid ) );
     315           0 :       ctx->sched_fds[ i ] = open( path, O_RDONLY );
     316           0 :       if( FD_UNLIKELY( -1==ctx->sched_fds[ i ] ) ) {
     317           0 :         if( FD_LIKELY( 2UL!=ctx->metrics[ i ][ FD_METRICS_GAUGE_TILE_STATUS_OFF ] ) ) FD_LOG_ERR(( "open sched failed (%i-%s)", errno, strerror( errno ) ));
     318           0 :         ctx->stat_fds[ i ] = -1;
     319           0 :       }
     320           0 :       break;
     321           0 :     }
     322           0 :   }
     323           0 : }
     324             : 
     325             : /* Read starttime (field 22) from stat file. Returns 0 on success, 1 if
     326             :    process died (ESRCH). */
     327             : 
     328             : static int
     329             : read_starttime( int     fd,
     330             :                 ulong   ns_per_tick,
     331           0 :                 ulong * out_starttime_nanos ) {
     332           0 :   char contents[ 4096 ] = {0};
     333           0 :   ulong contents_len = 0UL;
     334             : 
     335           0 :   while( 1 ) {
     336           0 :     if( FD_UNLIKELY( contents_len>=sizeof( contents ) ) ) FD_LOG_ERR(( "stat contents overflow" ));
     337           0 :     long n = read( fd, contents + contents_len, sizeof( contents ) - contents_len );
     338           0 :     if( FD_UNLIKELY( -1==n ) ) {
     339           0 :       if( FD_UNLIKELY( errno==ESRCH ) ) return 1;
     340           0 :       FD_LOG_ERR(( "read stat failed (%i-%s)", errno, strerror( errno ) ));
     341           0 :     }
     342           0 :     if( FD_LIKELY( 0L==n ) ) break;
     343           0 :     contents_len += (ulong)n;
     344           0 :   }
     345             : 
     346             :   /* Parse field 22 (starttime) from stat file */
     347           0 :   char * saveptr;
     348           0 :   char * token = strtok_r( contents, " ", &saveptr );
     349           0 :   ulong field_idx = 0UL;
     350             : 
     351           0 :   while( token && field_idx<21UL ) {
     352           0 :     token = strtok_r( NULL, " ", &saveptr );
     353           0 :     field_idx++;
     354           0 :   }
     355             : 
     356           0 :   if( FD_UNLIKELY( !token || field_idx!=21UL ) ) FD_LOG_ERR(( "starttime (field 22) not found in stat" ));
     357             : 
     358           0 :   char * endptr;
     359           0 :   ulong starttime_ticks = strtoul( token, &endptr, 10 );
     360           0 :   if( FD_UNLIKELY( *endptr!=' ' && *endptr!='\0' ) ) FD_LOG_ERR(( "strtoul failed for starttime" ));
     361           0 :   if( FD_UNLIKELY( starttime_ticks==ULONG_MAX ) ) FD_LOG_ERR(( "strtoul overflow for starttime" ));
     362             : 
     363           0 :   *out_starttime_nanos = starttime_ticks * ns_per_tick;
     364           0 :   return 0;
     365           0 : }
     366             : 
     367             : static void
     368             : unprivileged_init( fd_topo_t *      topo,
     369           0 :                    fd_topo_tile_t * tile ) {
     370           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     371             : 
     372           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     373           0 :   fd_diag_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_diag_tile_t), sizeof(fd_diag_tile_t) );
     374             : 
     375           0 :   memset( ctx->first_seen_died, 0, sizeof( ctx->first_seen_died ) );
     376           0 :   ctx->next_report_nanos = fd_log_wallclock();
     377             : 
     378             :   /* Read starttime (field 22) once at init for idle time calculation.
     379             :      CLK_TCK is always 100, so 1 tick = 10ms = 10,000,000 ns. */
     380           0 :   for( ulong i=0UL; i<ctx->tile_cnt; i++ ) {
     381           0 :     if( FD_LIKELY( -1!=ctx->stat_fds[ i ] ) ) {
     382           0 :       int died = read_starttime( ctx->stat_fds[ i ], 10000000UL, &ctx->starttime_nanos[ i ] );
     383           0 :       if( FD_UNLIKELY( died ) ) ctx->stat_fds[ i ] = -1;
     384           0 :     }
     385           0 :   }
     386             : 
     387           0 :   ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     388           0 :   if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
     389           0 :     FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
     390           0 : }
     391             : 
     392             : static ulong
     393             : populate_allowed_seccomp( fd_topo_t const *      topo,
     394             :                           fd_topo_tile_t const * tile,
     395             :                           ulong                  out_cnt,
     396           0 :                           struct sock_filter *   out ) {
     397           0 :   (void)topo;
     398           0 :   (void)tile;
     399             : 
     400           0 :   populate_sock_filter_policy_fd_diag_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
     401           0 :   return sock_filter_policy_fd_diag_tile_instr_cnt;
     402           0 : }
     403             : 
     404             : static ulong
     405             : populate_allowed_fds( fd_topo_t const *      topo,
     406             :                       fd_topo_tile_t const * tile,
     407             :                       ulong                  out_fds_cnt,
     408           0 :                       int *                  out_fds ) {
     409           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     410             : 
     411           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     412           0 :   fd_diag_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_diag_tile_t), sizeof(fd_diag_tile_t) );
     413             : 
     414           0 :   if( FD_UNLIKELY( out_fds_cnt<2UL+2UL*ctx->tile_cnt ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
     415             : 
     416           0 :   ulong out_cnt = 0UL;
     417           0 :   out_fds[ out_cnt++ ] = 2; /* stderr */
     418           0 :   if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
     419           0 :     out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
     420           0 :   for( ulong i=0UL; i<ctx->tile_cnt; i++ ) {
     421           0 :     if( -1!=ctx->stat_fds[ i ] )  out_fds[ out_cnt++ ] = ctx->stat_fds[ i ];  /* /proc/<pid>/task/<tid>/stat */
     422           0 :     if( -1!=ctx->sched_fds[ i ] ) out_fds[ out_cnt++ ] = ctx->sched_fds[ i ]; /* /proc/<pid>/task/<tid>/sched */
     423           0 :   }
     424           0 :   return out_cnt;
     425           0 : }
     426             : 
     427           0 : #define STEM_BURST (1UL)
     428           0 : #define STEM_LAZY  ((long)10e6) /* 10ms */
     429             : 
     430           0 : #define STEM_CALLBACK_CONTEXT_TYPE  fd_diag_tile_t
     431           0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_diag_tile_t)
     432             : 
     433           0 : #define STEM_CALLBACK_BEFORE_CREDIT before_credit
     434             : 
     435             : #include "../../disco/stem/fd_stem.c"
     436             : 
     437             : fd_topo_run_tile_t fd_tile_diag = {
     438             :   .name                     = "diag",
     439             :   .populate_allowed_seccomp = populate_allowed_seccomp,
     440             :   .populate_allowed_fds     = populate_allowed_fds,
     441             :   .scratch_align            = scratch_align,
     442             :   .scratch_footprint        = scratch_footprint,
     443             :   .privileged_init          = privileged_init,
     444             :   .unprivileged_init        = unprivileged_init,
     445             :   .run                      = stem_run,
     446             : };

Generated by: LCOV version 1.14