LCOV - code coverage report
Current view: top level - app/fddev - flame.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 142 0.0 %
Date: 2024-11-13 11:58:15 Functions: 0 5 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "fddev.h"
       3             : #include "../../util/net/fd_pcap.h"
       4             : 
       5             : #include <stdio.h>
       6             : #include <unistd.h>
       7             : #include <sys/wait.h>
       8             : 
       9             : static int record_pid;
      10             : 
      11             : static void
      12           0 : parent_signal( int sig ) {
      13           0 :   FD_LOG_NOTICE(( "Received signal %s\n", fd_io_strsignal( sig ) ));
      14           0 :   if( FD_LIKELY( record_pid ) ) {
      15           0 :     if( FD_UNLIKELY( -1==kill( record_pid, SIGINT ) ) ) FD_LOG_ERR(( "kill() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      16           0 :   }
      17           0 : }
      18             : 
      19             : static void
      20           0 : install_parent_signals( void ) {
      21           0 :   struct sigaction sa = {
      22           0 :     .sa_handler = parent_signal,
      23           0 :     .sa_flags   = 0,
      24           0 :   };
      25           0 :   if( FD_UNLIKELY( sigaction( SIGTERM, &sa, NULL ) ) )
      26           0 :     FD_LOG_ERR(( "sigaction(SIGTERM) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      27           0 :   if( FD_UNLIKELY( sigaction( SIGINT, &sa, NULL ) ) )
      28           0 :     FD_LOG_ERR(( "sigaction(SIGINT) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      29           0 : }
      30             : 
      31             : void
      32             : flame_cmd_perm( args_t *         args,
      33             :                 fd_caps_ctx_t *  caps,
      34           0 :                 config_t * const config ) {
      35           0 :   (void)args;
      36           0 :   (void)config;
      37             : 
      38           0 :   fd_caps_check_root( caps, "flame", "read system performance counters with `/usr/bin/perf`" );
      39           0 : }
      40             : 
      41             : void
      42             : flame_cmd_args( int *    pargc,
      43             :                 char *** pargv,
      44           0 :                 args_t * args ) {
      45             : 
      46           0 :   if( FD_UNLIKELY( !*pargc ) ) FD_LOG_ERR(( "usage: flame [all|tile|tile:idx|agave]" ));
      47           0 :   strncpy( args->flame.name, **pargv, sizeof( args->flame.name ) - 1 );
      48             : 
      49           0 :   (*pargc)--;
      50           0 :   (*pargv)++;
      51           0 : }
      52             : 
      53             : void
      54             : flame_cmd_fn( args_t *         args,
      55           0 :               config_t * const config ) {
      56           0 :   install_parent_signals();
      57             : 
      58           0 :   fd_topo_join_workspaces( &config->topo, FD_SHMEM_JOIN_MODE_READ_ONLY );
      59           0 :   fd_topo_fill( &config->topo );
      60             : 
      61           0 :   ulong tile_cnt = 0UL;
      62           0 :   ulong tile_idxs[ 128UL ];
      63             : 
      64           0 :   int whole_process = 0;
      65           0 :   if( FD_UNLIKELY( !strcmp( "all", args->flame.name ) ) ) {
      66           0 :     FD_TEST( config->topo.tile_cnt<sizeof(tile_idxs)/sizeof(tile_idxs[0]) );
      67           0 :     for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
      68           0 :       tile_idxs[ tile_cnt ] = i;
      69           0 :       tile_cnt++;
      70           0 :     }
      71           0 :   } else if( FD_UNLIKELY( !strcmp( "agave", args->flame.name ) ) ) {
      72             :     /* Find the bank tile so we can get the Agave PID */
      73           0 :     ulong bank_tile_idx = fd_topo_find_tile( &config->topo, "bank", 0UL );
      74           0 :     if( FD_UNLIKELY( bank_tile_idx==ULONG_MAX ) ) FD_LOG_ERR(( "tile `bank` not found" ));
      75           0 :     whole_process = 1;
      76           0 :     tile_idxs[ 0 ] = bank_tile_idx;
      77           0 :     tile_cnt = 1UL;
      78           0 :   } else {
      79           0 :     char * sep = strchr( args->flame.name, ':' );
      80             : 
      81           0 :     ulong tile_idx;
      82           0 :     if( FD_UNLIKELY( !sep ) ) {
      83           0 :       tile_idx = fd_topo_find_tile( &config->topo, args->flame.name, 0UL );
      84           0 :     } else {
      85           0 :       char * endptr;
      86           0 :       *sep = '\0';
      87           0 :       ulong kind_id = strtoul( sep+1, &endptr, 10 );
      88           0 :       if( FD_UNLIKELY( *endptr!='\0' || kind_id==ULONG_MAX ) ) FD_LOG_ERR(( "invalid tile kind id provided `%s`", sep+1 ));
      89           0 :       tile_idx = fd_topo_find_tile( &config->topo, args->flame.name, kind_id );
      90           0 :     }
      91             : 
      92           0 :     if( FD_UNLIKELY( tile_idx==ULONG_MAX ) ) FD_LOG_ERR(( "tile `%s` not found", args->flame.name ));
      93           0 :     tile_idxs[ 0 ] = tile_idx;
      94           0 :     tile_cnt = 1UL;
      95           0 :   }
      96             : 
      97           0 :   char threads[ 4096 ] = {0};
      98           0 :   ulong len = 0UL;
      99           0 :   for( ulong i=0UL; i<tile_cnt; i++ ) {
     100           0 :     if( FD_LIKELY( i!=0UL ) ) {
     101           0 :       FD_TEST( fd_cstr_printf_check( threads+len, sizeof(threads)-len, NULL, "," ) );
     102           0 :       len += 1UL;
     103           0 :     }
     104             : 
     105           0 :     ulong tid = fd_metrics_tile( config->topo.tiles[ tile_idxs[ i ] ].metrics )[ FD_METRICS_GAUGE_TILE_TID_OFF ];
     106           0 :     ulong pid = fd_metrics_tile( config->topo.tiles[ tile_idxs[ i ] ].metrics )[ FD_METRICS_GAUGE_TILE_PID_OFF ];
     107             : 
     108           0 :     FD_TEST( pid<=INT_MAX );
     109           0 :     if( FD_UNLIKELY( -1==kill( (int)pid, 0 ) ) ) {
     110           0 :       if( FD_UNLIKELY( errno==ESRCH ) ) FD_LOG_ERR(( "tile %s:%lu is not running", config->topo.tiles[ i ].name, config->topo.tiles[ i ].kind_id ));
     111           0 :       else                              FD_LOG_ERR(( "kill() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     112           0 :     }
     113             : 
     114           0 :     ulong arg_len;
     115           0 :     FD_TEST( fd_cstr_printf_check( threads+len, sizeof(threads)-len, &arg_len, "%lu", fd_ulong_if( whole_process, pid, tid ) ) );
     116           0 :     len += arg_len;
     117           0 :   }
     118           0 :   FD_TEST( len<sizeof(threads) );
     119             : 
     120           0 :   FD_LOG_NOTICE(( "/usr/bin/perf script record flamegraph -o - -F 99 -%c %s | /usr/bin/perf script report flamegraph -i -", fd_char_if( whole_process, 'p', 't' ), threads ));
     121             : 
     122           0 :   int pipefd[ 2 ];
     123           0 :   if( FD_UNLIKELY( -1==pipe( pipefd ) ) ) FD_LOG_ERR(( "pipe() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     124             : 
     125           0 :   record_pid = fork();
     126           0 :   if( FD_UNLIKELY( -1==record_pid ) ) FD_LOG_ERR(( "fork() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     127           0 :   if( FD_LIKELY( !record_pid ) ) {
     128           0 :     if( FD_UNLIKELY( -1==close( pipefd[ 0 ] ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     129           0 :     if( FD_UNLIKELY( -1==dup2( pipefd[ 1 ], STDOUT_FILENO ) ) ) FD_LOG_ERR(( "dup2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     130           0 :     if( FD_UNLIKELY( -1==close( pipefd[ 1 ] ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     131             : 
     132           0 :     char * args[ 11 ] = {
     133           0 :       "/usr/bin/perf",
     134           0 :       "script",
     135           0 :       "record",
     136           0 :       "flamegraph",
     137           0 :       "-o",
     138           0 :       "-",
     139           0 :       "-F",
     140           0 :       "99",
     141           0 :       whole_process ? "-p" : "-t",
     142           0 :       threads,
     143           0 :       NULL,
     144           0 :     };
     145           0 :     if( FD_UNLIKELY( -1==execve( "/usr/bin/perf", (char * const *)args, NULL ) ) ) FD_LOG_ERR(( "execve() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     146           0 :   }
     147             : 
     148           0 :   int report_pid = fork();
     149           0 :   if( FD_UNLIKELY( -1==report_pid ) ) FD_LOG_ERR(( "fork() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     150           0 :   if( FD_LIKELY( !report_pid ) ) {
     151           0 :     if( FD_UNLIKELY( -1==close( pipefd[ 1 ] ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     152           0 :     if( FD_UNLIKELY( -1==dup2( pipefd[ 0 ], STDIN_FILENO ) ) ) FD_LOG_ERR(( "dup2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     153           0 :     if( FD_UNLIKELY( -1==close( pipefd[ 0 ] ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     154           0 :     if( FD_UNLIKELY( -1==setpgid( 0, 0 ) ) ) FD_LOG_ERR(( "setpgid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     155             : 
     156           0 :     char * args[ 7 ] = {
     157           0 :       "/usr/bin/perf",
     158           0 :       "script",
     159           0 :       "report",
     160           0 :       "flamegraph",
     161           0 :       "-i",
     162           0 :       "-",
     163           0 :       NULL,
     164           0 :     };
     165           0 :     if( FD_UNLIKELY( -1==execve( "/usr/bin/perf", (char * const *)args, NULL ) ) ) FD_LOG_ERR(( "execve() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     166           0 :   }
     167             : 
     168           0 :   if( FD_UNLIKELY( -1==close( pipefd[ 0 ] ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     169           0 :   if( FD_UNLIKELY( -1==close( pipefd[ 1 ] ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     170             : 
     171           0 :   FD_LOG_NOTICE(( "Perf collection running. Send SIGINT / Crl+C to stop." ));
     172             : 
     173           0 :   ulong exited_cnt = 0UL;
     174           0 :   while( FD_UNLIKELY( exited_cnt<2UL ) ) {
     175           0 :     int wstatus;
     176           0 :     int exited_pid = waitpid( -1, &wstatus, 0 );
     177           0 :     if( FD_UNLIKELY( -1==exited_pid ) ) {
     178           0 :       if( FD_LIKELY( errno==EAGAIN || errno==EINTR ) ) continue;
     179           0 :       FD_LOG_ERR(( "waitpid() failed (%d-%s)", errno, fd_io_strerror( errno ) ));
     180           0 :     }
     181             : 
     182           0 :     char const * process_name = exited_pid==record_pid ? "record" : "report";
     183             : 
     184           0 :     int record_graceful = exited_pid==record_pid && !WIFEXITED( wstatus ) && WTERMSIG( wstatus )==SIGINT;
     185             : 
     186           0 :     if( FD_UNLIKELY( !WIFEXITED( wstatus ) && !record_graceful ) ) FD_LOG_ERR(( "perf %s exited unexpectedly with signal %d (%s)", process_name, WTERMSIG( wstatus ), fd_io_strsignal( WTERMSIG( wstatus ) ) ));
     187           0 :     if( FD_UNLIKELY( WEXITSTATUS( wstatus ) && !record_graceful ) ) FD_LOG_ERR(( "perf %s exited unexpectedly with code %d", process_name, WEXITSTATUS( wstatus ) ));
     188             : 
     189           0 :     exited_cnt++;
     190           0 :   }
     191             : 
     192           0 :   exit_group( 0 );
     193           0 : }

Generated by: LCOV version 1.14