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