#!/usr/bin/env bpftrace

/* Script to obtain sys_write() latency histograms.
 * It will measure time between entry and exit and plot one histogram
 * for each destination port number, indicating the amount of time spent.
 *
 * Implemented 2026 by Pau Espin Pedrol <pespin@sysmocom.de>
 * SPDX-License-Identifier: CC0
 *
 * As no filtering on PID etc. is done, you will likely use this with 'bpftrace -p' like
 *
 *     bpftrace ./sys_write.bt -p PID
 *
 * (where PID is the PID of the process, like osmo-bts-trx)
 */

BEGIN
{
  printf("Tracing sys_write() latency... Hit Ctrl-C to end.\n");
}

tracepoint:syscalls:sys_enter_write / comm == str($1) /
{
  @start[tid] = nsecs;
  @write_fd[tid] = args->fd;
  @write_buf[tid] = args->buf;
  @write_count[tid] = args->count;
}

kfunc:vfs_write / @start[tid] /
{
  $delta_us = (nsecs - @start[tid]) / 1000;
  @vfs_write_file[tid] = args->file;
  @vfs_write_delta_us[tid] = $delta_us;
  //printf("PESPIN: kfunc vfs_write delta=%d us, file->f_flags=0x%x\n", @vfs_write_delta_us[tid], @vfs_write_file[tid]->f_flags);
}

tracepoint:syscalls:sys_exit_write / @start[tid] /
{
  $delta_us = (nsecs - @start[tid]) / 1000;

  if ($delta_us >= 400000U) {
    printf("PESPIN: PID %d detected long write(fd=%d, count=%d, ret=%d): %d us\n", pid, @write_fd[tid], @write_count[tid], args->ret, $delta_us);
    printf("PESPIN: vfs_write delta=%d us, file->f_flags=0x%x\n", @vfs_write_delta_us[tid], @vfs_write_file[tid]->f_flags);
    if (!(@vfs_write_file[tid]->f_flags & 0x800)) { // O_NONBLOCK is 0x800 in hex (04000 in octal)
      printf("PESPIN: O_NONBLOCK unset!!!\n");
    }
    printf("PESPIN: sys_write content: %s\n", str(@write_buf[tid], @write_count[tid]));
    printf("stack trace of write():\n%s\n", ustack);
    @[ustack()] = count();
  }

  @latency[@write_fd[tid]] = hist($delta_us);

  delete(@start[tid]);
  delete(@write_fd[tid]);
  delete(@write_buf[tid]);
  delete(@write_count[tid]);
  delete(@vfs_write_file[tid]);
  delete(@vfs_write_delta_us[tid]);
}

/* vim:set ts=2 sw=2 et: */
