Repository: sharkdp/hyperfine
File: src/timer/mod.rs (Rust)

Code before:
    pub time_real: Second,
    pub time_user: Second,
    pub time_system: Second,

    /// The exit status of the process
    pub status: ExitStatus,
}

/// Discard the output of a child process.
fn discard(output: ChildStdout) {
    const CHUNK_SIZE: usize = 64 << 10;

    #[cfg(target_os = "linux")]
    {
        if let Ok(file) = File::create("/dev/null") {
            while let Ok(bytes) = splice(
                output.as_raw_fd(),
                None,
                file.as_raw_fd(),
                None,
                CHUNK_SIZE,
                SpliceFFlags::empty(),
            ) {
                if bytes == 0 {
                    break;
                }
            }
        }
    }

    #[cfg(not(target_os = "linux"))]
    {
        let mut output = output;
        let mut buf = [0; CHUNK_SIZE];
        while let Ok(bytes) = output.read(&mut buf) {
            if bytes == 0 {
                break;
            }
        }
    }
}

/// Execute the given command and return a timing summary
pub fn execute_and_measure(mut command: Command) -> Result<TimerResult> {
    let wallclock_timer = WallClockTimer::start();

    let mut child = command.spawn()?;
    let output = child.stdout.take();

    #[cfg(not(windows))]
    let cpu_timer = self::unix_timer::CPUTimer::start();

Review comment (bug):
There are two potential error cases here.

* If `File::create("/dev/null")` fails (I have no idea if that can happen?), we would skip the entire `while` loop and not read from `output` at all... potentially blocking the benchmarked program?
* `splice` has been in Linux kernels since 2006. But I'm curious what would happen if we ran this on older (or somhow modified) kernels without a `splice` syscall. Would it fail during startup of hyperfine, since the corresponding wrapper in libc wouldn't be available? Or crash with `ENOSYS`? More importantly: is is something we should worry about, or do you think we can safely ignore it?

Code after:
    pub time_system: Second,

    /// The exit status of the process
    pub status: ExitStatus,
}

/// Discard the output of a child process.
fn discard(output: ChildStdout) {
    const CHUNK_SIZE: usize = 64 << 10;

    #[cfg(target_os = "linux")]
    {
        if let Ok(file) = File::create("/dev/null") {
            while let Ok(bytes) = splice(
                output.as_raw_fd(),
                None,
                file.as_raw_fd(),
                None,
                CHUNK_SIZE,
                SpliceFFlags::empty(),
            ) {
                if bytes == 0 {
                    break;
                }
            }
        }
    }

    let mut output = output;
    let mut buf = [0; CHUNK_SIZE];
    while let Ok(bytes) = output.read(&mut buf) {
        if bytes == 0 {
            break;
        }
    }
}

/// Execute the given command and return a timing summary
pub fn execute_and_measure(mut command: Command) -> Result<TimerResult> {
    let wallclock_timer = WallClockTimer::start();

    #[cfg(not(windows))]
    let cpu_timer = self::unix_timer::CPUTimer::start();

    let mut child = command.spawn()?;

    #[cfg(windows)]
    let cpu_timer = self::windows_timer::CPUTimer::start_for_process(&child);

    if let Some(output) = child.stdout.take() {
        // Handle CommandOutputPolicy::Pipe